在C#中使用强类型发件人的EventHandler

Pol*_*ity 6 .net c# event-handling

令我恼火的一件事是,在默认事件中,Sender属于object类型,因此在我们使用它之前几乎总是需要手动转换.幸运的是,由于VB现在也支持委托中的差异,我们可以以强类型发送者的方式更新事件的签名,请参阅:事件参数; "发件人为对象",或"发件人为T"?

遗憾的是,这对于发送者属于object类型的现有声明事件不起作用.

现在一个解决方案就是生成一个假的EventHandler,它在内部为你处理演员表.我做了一个简单的例子,见:

struct EventHandler<TSender, TEventArgs>
    where TEventArgs: EventArgs
{
    private readonly Action<TSender, TEventArgs> _delegate;

    public EventHandler(Action<TSender, TEventArgs> @delegate)
    {
        if (@delegate == null)
            throw new ArgumentNullException("@delegate");

        _delegate = @delegate;
    }

    public static implicit operator EventHandler<TEventArgs>(EventHandler<TSender, TEventArgs> eventHandler)
    {
        return new EventHandler<TEventArgs>(eventHandler.Execute);
    }

    private void Execute(object sender, EventArgs e)
    {
        TSender typedSender = (TSender)sender;
        TEventArgs typedEventArgs = (TEventArgs)e;

        _delegate(typedSender, typedEventArgs);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以按照您的预期使用它:

class Program
{
    event EventHandler<EventArgs> Test;

    static void Main(string[] args)
    {
        new Program().Main();
    }

    void Main()
    {
        Test += new EventHandler<Program, EventArgs>(TestEventHandler);

        Test(this, EventArgs.Empty);
    }

    void TestEventHandler(Program sender, EventArgs e)
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我真的想要使用它,那么还有很多工作要做.(结构应该像原始委托一样).然而我确实感觉已经有一个很好的实现,或者没有实现,因为我忽略了一些主要的缺点.

谁能回答我上面提到的问题?还有其他提示吗?

Muh*_*han 4

我想不出任何比以下代码更少的解决方案

var original = (OriginalType)sender;
Run Code Online (Sandbox Code Playgroud)

另外,如果类是您的,那么没有什么可以阻止您创建自己的委托而不是 EventHandler 委托

delegate void EventHandler<in TSender, in TArgs>(TSender sender, TArgs args);
Run Code Online (Sandbox Code Playgroud)

这是 args 和 sender 的逆变

人们通常还拥有引发事件的对象的引用,因此他们很少需要从发送者那里获取该内容。在你的情况下有可能吗?

编辑:既然您提到您正在处理不是由您编写的事件,因此修改委托是不可能的,并且您可能没有对该对象的引用,因此在这种情况下您必须求助于发送者。现在,在您的解决方案中,您无法取消订阅该事件。如果您修改它以支持这一点,那么您将必须保留对您的这个结构的引用,这比简单的转换需要更多的工作。我认为铸造仍然是最干净的解决方案。