Как вручную вызвать событие? - PullRequest
22 голосов
/ 05 января 2012

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

_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();
    }
}

Ответы [ 9 ]

20 голосов
/ 05 января 2012

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

20 голосов
/ 05 января 2012

Можно ли это сделать с помощью обычного C #? Нет ( как указано ранее ). Но с помощью отражения это возможно. Вот несколько проверенных кодов, основанных на ответе на этой ветке форума 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 голосов
/ 05 января 2012

Это обходной путь, вы не можете перебрать событие Elapsed.Но чтобы вызвать их всех, пусть таймер сделает всю работу.Этот код для 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)

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

2 голосов
/ 05 января 2012

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

public void RunAllFuncs()
{
   _somefunction1();
   _somefunction2();
   _somefunction3();
}
1 голос
/ 01 мая 2018

Хорошо, я заканчиваю здесь поиском, как просто запустить событие, которое не имеет никаких пользовательских аргументов или чего-то еще. Я знаю, что вопрос ОП отличается! но я хотел бы поделиться, я надеюсь, что это кому-то поможет.

Не упрощенная версия:

 var Handler = EventNameHere;
        if (Handler != null)
        {
            Handler(this, EventArgs.Empty);
        }

Упрощенная версия:

 EventNameHere?.Invoke(this, EventArgs.Empty);
1 голос
/ 05 января 2012

Я думаю, что вам, вероятно, нужно использовать 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;

Удачи!

0 голосов
/ 24 июня 2016

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

Заменено 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);
        }
    }
0 голосов
/ 05 января 2012

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

this.ElapsedTick(this, eventArgs);

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

0 голосов
/ 05 января 2012

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

ElapsedTick(this, new EventArgs());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...