如何手动调用事件?

时间:2012-01-04 22:02:10

标签: c# events

我在C#中有以下行:

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

如何在不指定_somefunction的情况下调用订阅_timer.ElapsedTick的所有方法?沿着这条伪线的某个地方

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 个答案:

答案 0 :(得分:20)

可以使用传统的C#完成吗?不(as previously stated)。但使用反射是可能的。以下是一些基于this MSDN forum thread答案的测试代码:

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

}

<强>更新

我不熟悉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);
    }
} 

答案 1 :(得分:18)

您无法调用由其他类型拥有的事件。只能从声明它的类内部调用事件。

答案 2 :(得分:2)

你可以创建一个运行它们的函数:

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

答案 3 :(得分:2)

这是一个解决方法,你不能遍历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)

这样的事情将触发事件,但您的原始间隔将重新启动。如果你想保留原始的刻度模式,你可能需要在那里做一些数学运算。

答案 4 :(得分:1)

我认为您可能需要使用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;

祝你好运!

答案 5 :(得分:0)

基于上面的M.Babcock's answer,有一些轻微的反射方法更新。

GetField替换为GetTypeInfoGetDeclaredField,将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);
        }
    }

答案 6 :(得分:0)

我最终在这里搜索如何简单地启动事件,没有任何自定义args或任何东西。我知道OP问题不同!但我想分享,我希望它可以帮助别人。

不简化版本:

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

简化版本:

 EventNameHere?.Invoke(this, EventArgs.Empty);

答案 7 :(得分:-1)

根据ElapsedTick事件的签名,您可以通过在声明它的类中调用它来触发事件。例如:

ElapsedTick(this, new EventArgs());

答案 8 :(得分:-1)

您只能从声明它的类中调用事件。如果您编写了计时器类,则可以这样调用它:

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类之外的委托中调用它们。