C# 静态事件处理程序与非静态事件处理程序

C# static event handler vs non static event handler

美好的一天!我想了解以下问题:

假设我们有简单的 EventSubscriber class

public class EventSubscriber
{
    public static Delegate AddEventHandler(object target, string eventName, Action<object, EventArgs> action)
    {
        EventInfo eventInfo = target.GetType().GetEvent(eventName);
        Delegate handler  = Delegate.CreateDelegate(eventInfo.EventHandlerType, action.Method); 
        eventInfo.AddEventHandler(target, handler);
        return handler;
    }

    public static void RemoveEventHandler(object target, string eventName, Delegate handler)
    {
        var eventInfo = target.GetType().GetEvent(eventName);
        eventInfo.RemoveEventHandler(target, handler);
    }
}

假设我们有一个定时器,我们希望订阅 Elapsed 事件。

class Program
{
    static System.Timers.Timer timer;
    public static void InitTimer(int interval)
    {
        timer = new System.Timers.Timer(interval);
        timer.Start();
    }
    static void Main(string[] args)
    {
        int interval = 1000;
        InitTimer(interval);
        var handler = EventSubscriber.AddEventHandler(timer, "Elapsed", Handler);
        Thread.Sleep(Convert.ToInt16(interval * 5));
        EventSubscriber.RemoveEventHandler(timer, "Elapsed", handler);
        Thread.Sleep(Convert.ToInt16(interval * 5));
    }

    public static void Handler(object sender, EventArgs args)
    {
        Console.WriteLine("BOOO");
    }
}

现在,如果您编译此应用程序,一切都会正常工作,您将看到应用程序的扩展行为。 让我们将计时器包装在 class:

public class TimerWrapper
{
    public System.Timers.Timer Timer { get; set; }
    public int Interval { get; set; }
    public TimerWrapper(int interval)
    {
        Interval = interval;
        Timer = new System.Timers.Timer(Interval);
        Timer.Start();
    }
    public static void Handler(object sender, EventArgs args)
    {
        Console.WriteLine("BOOO");
    }
}

现在让我们来看看:

class Program
{
    static void Main(string[] args)
    {
        int interval = 1000;
        TimerWrapper timerWrapper = new TimerWrapper(interval);
        var handler = EventSubscriber.AddEventHandler(timerWrapper.Timer, "Elapsed", TimerWrapper.Handler);
        Thread.Sleep(Convert.ToInt16(interval * 5));
        EventSubscriber.RemoveEventHandler(timerWrapper.Timer, "Elapsed", handler);
        Thread.Sleep(Convert.ToInt16(interval * 5));
    }
}

一切正常。但是,如果我们将 TimerWrapper 中的处理程序设置为非静态和 运行 应用程序怎么办?我们将收到 System.ArgumentException 和下一条消息 "Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type."

我有假设为什么会这样,但我想坚定地知道它。

我希望得到全面的答复,提前致谢并感谢您的宝贵时间!

问题是您调用 Delegate.CreateDelegate 时使用了预计适用于静态方法的重载(或者对于有额外委托参数作为方法调用目标的实例方法)。

要让它工作,您需要做的就是在创建新委托时传入现有委托的目标:

Delegate handler = Delegate.CreateDelegate(
    eventInfo.EventHandlerType,
    action.Target,
    action.Method); 

如果原始委托 (action) 使用静态方法,action.Target 已经是 null,所以没关系。