将事件作为参数传递给方法

alt*_*tso 41 c# events

可能重复:
如何将事件传递给方法?

是否可以将事件作为参数传递给方法?

例如,以下方法订阅事件,确实有效,并取消订阅事件:

void SubscribeDoAndUnsubscribe<TElement, TEventArgs>(
        IEnumerable<TElement> elements,
        ??? elementEvent)
    where TEventArgs: EventArgs
{
    EventHandler<TEventArgs> handler = (sender, e) => { /* Handle an event */ };

    foreach (var element in elements)
    {
         // Subscribe somehow
         element.elementEvent += handler
    }

    // Do things

    foreach (var element in elements)
    {
         // Unsubscribe somehow
         element.elementEvent -= handler
    }
}
Run Code Online (Sandbox Code Playgroud)

客户代码:

var elements = new [] { new Button(), new Button() };
SubscribeDoAndUnsubscribe(elements, ??? /* e => e.Click */);
Run Code Online (Sandbox Code Playgroud)

如果不可能,我如何以其他方式实现类似的逻辑?我应该为订阅/取消订阅方法传递一对代表吗?

Eri*_*ert 43

事实上你发现事件不是C#中的"头等"; 你不能将事件作为数据传递.您可以通过创建委托将委托传递给与接收者关联的方法作为第一类对象.您可以将对任何变量的引用作为(主要)第一类对象传递.(我说"大多是"因为对变量的引用不能存储在字段中,存储在阵列,等等;它们是高度限制相对于其他类型的数据)可以绕过一个类型通过获取其类型对象并将该周围.

但是没有办法直接将数据作为与特定实例关联的事件,属性,索引器,构造函数或析构函数传递.你可以做的最好的事情是按照你的建议,从一个lambda中创建一个委托(或一对委托).或者,获取与事件关联的反射对象,并将其与实例一起传递.

  • 你没有传递一个事件,你正在传递一个代表. (2认同)

Jon*_*eet 32

不,不幸的是没有.

如果你看一下Reactive Extensions,那就会遇到类似的问题.他们使用了三种选择(IIRC - 从我看过以来已经有一段时间了):

  • 传递相应的EventInfo并用反射调用它
  • 传递事件的名称(如果需要,传递目标)并用反射调用它
  • 通过代表订阅和取消订阅

在后一种情况下的调用将是这样的:

SubscribeAndDoUnsubscribe(elements,
                          handler => e.Click += handler,
                          handler => e.Click -= handler);
Run Code Online (Sandbox Code Playgroud)

并且声明将是:

void SubscribeDoAndUnsubscribe<TElement, TEventArgs>(
        IEnumerable<TElement> elements,
        Action<EventHandler<TEventArgs>> subscription,
        Action<EventHandler<TEventArgs>> unsubscription)
    where TEventArgs: EventArgs
Run Code Online (Sandbox Code Playgroud)