Подтвердить что ты не робот

Как вручную вызывать событие?

У меня есть следующая строка в С#:

_timer.ElapsedTick += _somefunction1;
_timer.ElapsedTick += _somefunction2;
_timer.ElapsedTick += _somefunction3;

Как вызывать все методы, подписанные на _timer.ElapsedTick, без указания функции _some? Где-то вдоль этой псевдо-линии

invoke(_timer.ElapsedTick);

Ваша помощь очень ценится.

Обновление

Пример из @M.Babcock работает. Метод FireEvent делает магию. Спасибо.

class InvokeFromMe
{
    public event EventHandler RaiseMe;
}
class MainClass
{
    public MainClass()
    {
        InvokeFromMe fromMe = new InvokeFromMe();
        fromMe.RaiseMe += fromMe_RaiseMe;
        fromMe.RaiseMe += fromMe_RaiseMe1;
        FireEvent(fromMe, "RaiseMe", null, EventArgs.Empty);
        //works

        System.Timers.Timer _timer = new System.Timers.Timer();
        _timer.Elapsed += _timer_Elapsed;
        FireEvent(_timer, "onIntervalElapsed", null, null);
        //throws exception
    }
    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("_timer_Elapsed raised");
    }
    private void fromMe_RaiseMe(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 0 Raised");
    }
    private void fromMe_RaiseMe1(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 1 Raised");
    }
    public void FireEvent(object onMe, string invokeMe, params object[] eventParams)
    {
        MulticastDelegate eventDelagate =
              (MulticastDelegate)onMe.GetType().GetField(invokeMe,
               System.Reflection.BindingFlags.Instance |
               System.Reflection.BindingFlags.NonPublic).GetValue(onMe);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.Method.Invoke(dlg.Target, eventParams);
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        MainClass m = new MainClass();
    }
}
4b9b3361

Ответ 1

Можно ли это сделать с помощью обычного С#? Нет (как указано ранее). Но использование отражения возможно. Вот несколько проверенных кода, основанных на ответе на этот поток форума MSDN:

class InvokeFromMe
{
    public event EventHandler RaiseMe;
}

class Program
{
    static void Main(string[] args)
    {
        var fromMe = new InvokeFromMe();

        fromMe.RaiseMe += fromMe_RaiseMe;
        fromMe.RaiseMe += fromMe_RaiseMe1;
        fromMe.RaiseMe += fromMe_RaiseMe2;

        FireEvent(fromMe, "RaiseMe", null, EventArgs.Empty);
    }

    static void fromMe_RaiseMe(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 0 Raised");
    }
    static void fromMe_RaiseMe1(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 1 Raised");
    }
    static void fromMe_RaiseMe2(object sender, EventArgs e)
    {
        Console.WriteLine("Event Handler 2 Raised");
    }

    public static void FireEvent(object onMe, string invokeMe, params object[] eventParams)
    {
        MulticastDelegate eventDelagate =
              (MulticastDelegate)onMe.GetType().GetField(invokeMe,
               System.Reflection.BindingFlags.Instance |
               System.Reflection.BindingFlags.NonPublic).GetValue(onMe);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.Method.Invoke(dlg.Target, eventParams);
        }
    } 

}

UPDATE

Я не знаком с классом System.Timer.Timer, поэтому я не уверен, что отличается от моего приведенного примера. Вы могли бы попробовать что-то вроде:

public static void FirePublicEvent(object onMe, string invokeMe, params object[] eventParams)
{
    MulticastDelegate eventDelagate =
          (MulticastDelegate)onMe.GetType().GetField(invokeMe,
           System.Reflection.BindingFlags.Instance |
           System.Reflection.BindingFlags.Public).GetValue(onMe);

    Delegate[] delegates = eventDelagate.GetInvocationList();

    foreach (Delegate dlg in delegates)
    {
       dlg.Method.Invoke(dlg.Target, eventParams);
    }
} 

Ответ 2

Вы не можете вызывать событие, принадлежащее другому типу. Событие может вызываться только из класса, объявляющего его.

Ответ 3

Это работа вокруг, вы не можете пройти через событие Истекшее. Но чтобы вызвать их всех, пусть таймер выполнит работу. Этот код для System.Timer, не уверен, какой таймер вы используете.

Предполагая, что таймер уже включен:

int interval = timer.Interval;
ElapsedEventHandler handler = null;
handler = (s,e) =>
{
    timer.Interval = interval; // put interval back to original value
    timer.Elapsed -= handler;
};
timer.Elapsed += handler;
timer.Interval = 1; // 1 millisecond, pretty much going to fire right now (as soon as you let it)

Что-то вроде этого упустит события, но исходный интервал будет перезапущен. Возможно, вам придется сделать некоторую математику, если вы хотите сохранить исходный тик.

Ответ 4

Вы можете создать функцию, которая запускает их все:

public void RunAllFuncs()
{
   _somefunction1();
   _somefunction2();
   _somefunction3();
}

Ответ 5

Думаю, вам, вероятно, нужно использовать InvokeMember:

public void GetMethod(string methodName){

            var args = new Object[] { [INSERT ARGS IF NECESSARY--SET TO NULL OTHERWISE] };
            try
            {
                var t = new [INSERT NAME OF CLASS THAT CONTAINS YOUR METHOD]();
                Type typeInfo = t.GetType();
                var result = typeInfo.InvokeMember(methodName, BindingFlags.InvokeMethod, null, t, args);
                return result;
            }
            catch (Exception ex)
            {
                return ex;
            }
}

Затем назовите его следующим образом:

_timer.ElapsedTick += GetMethod("[INSERT METHOD NAME AS STRING]");

Обязательно укажите это:

using System.Reflection;

Удачи!

Ответ 6

Основываясь на ответе М.Бабкока выше, с некоторыми небольшими обновлениями метода отражения.

Замените GetField на GetTypeInfo и GetDeclaredField, а dlg.Method на dlg.GetMethodInfo.

    using System.Reflection;

    ...

    public static void FireEvent(this object onMe, string invokeMe, params object[] eventParams)
    {
        TypeInfo typeInfo = onMe.GetType().GetTypeInfo();
        FieldInfo fieldInfo = typeInfo.GetDeclaredField(invokeMe);
        MulticastDelegate eventDelagate = (MulticastDelegate)fieldInfo.GetValue(onMe);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.GetMethodInfo().Invoke(dlg.Target, eventParams);
        }
    }

Ответ 7

В зависимости от сигнатуры события ElapsedTick вы можете запустить событие, вызвав его как метод из класса, в котором он объявлен. Например:

ElapsedTick(this, new EventArgs());

Ответ 8

Вы можете вызывать события только внутри класса, объявляющего его. Если вы написали класс таймера, вы должны вызвать его следующим образом:

this.ElapsedTick(this, eventArgs);

Вне класса таймера вы можете сделать следующее:

delegate void delegateSample(object sender, EventArgs e);

delegateSample d;
d += new delegateSample(_somefunction1);
d += new delegateSample(_somefunction2);
d(this, EventArgs.Empty);

delegateSample действительно должен быть типом события ElapsedTick, вместо объявления другого типа делегата. Я просто не знал имени этого делегата. Просто убедитесь, что вы добавляете каждую функцию в событие ElapsedTick и переменную делегата, которую вы объявляете, и вы можете вызывать их все из делегата вне класса Timer.