1

目前,我使用以下代码在一个类中实现一个事件,该事件最多可以注册一个事件处理程序:

private event EventHandler<EventArgs> e_Foo;

public event EventHandler<EventArgs> Foo {
    add {
        if (e_Foo != null && e_Foo.GetInvocationList().Any())
            throw new InvalidOperationException("Only one event handler may be registered at a time.");
        e_Foo += value;
    }
    remove {
        e_Foo -= value;
    }
}

private void OnFoo() {
    if (e_Foo != null)
        e_Foo(this, EventArgs.Empty);
}
  • 有没有更好的办法?
  • 有什么办法可以将它包装在一个类中,这样我就不必复制和粘贴这么多代码了?
4

4 回答 4

2

这真的应该是一个评论,但我需要编写代码:

private void OnFoo() {
    if (e_Foo != null)
        e_Foo(this, EventArgs.Empty);
}

引入了潜在的竞争条件,因为调用列表可能会在检查和实际调用之间发生变化。您最终可能会调用 null。它应该是:

private void OnFoo() {
    var fuFoo = e_Foo;
    if (fuFoo != null)
        fuFoo(this, EventArgs.Empty);
}

注意:现在是 2020 年,从 C# 6 开始,我们有了空条件运算符

这可以用来以更简单的方式表达前面的代码:

private void OnFoo() {
    e_Foo?.Invoke(this, EventArgs.Empty);
}

我想一种不易出错的方法是一种更好的方法。我赢了!

于 2012-09-19T00:27:47.933 回答
2

事件只是以特殊语义公开委托属性的一种特殊方式:您无需设置值,而是添加和删除处理程序。如果此行为对您不起作用,那么尝试将其从事件中删除只会造成不必要的复杂性。相反,为什么不直接将回调公开为委托属性来避免添加您不想要的行为呢?

public Action<T1, T2> Foo {get; set;}

private void OnFoo(T1, T2) 
{
    var handler = Foo;
    if(handler != null) handler(T1, T2);
}

这样,当有人设置OnFoo它时,它将使用正常的属性语义并替换委托实例,而不是将其扔在一堆。它并没有摆脱多播,但在我看来,这并不是你的问题。

于 2012-12-22T13:58:37.040 回答
1

我认为不可能大量减少代码,但是您可以将检查放入为您完成工作的方法中,或者返回处理程序,如下所示:

public EventHandler<T> HookUp<T>(EventHandler<T> myEvent, EventHandler<T> myMethod)
    where T : EventArgs
{
    if (myEvent != null && myEvent.GetInvocationList().Any())
        throw new InvalidOperationException("Only one event handler may be registered at a time.");
    return myMethod;
}

private event EventHandler<EventArgs> e_Foo;

public event EventHandler<EventArgs> Foo
{
    add { e_Foo += HookUp(e_Foo, value); }
    remove { e_Foo -= value; }
}

您可以在某些扩展方法中实现一个具有所有逻辑的接口,或者继承一个抽象类。但是,您必须为所需的每个事件数(ISingleSubscriberOneISingleSubscriberTwoISingleSubscriberThree等)拥有多个接口。

于 2012-12-22T13:42:01.693 回答
0

我不确定在您的场景中是否可行,但我可能会将事件代码分配给 Action 变量并将事件链接到该 Action。然后,用户将只能更改操作,而永远不会真正更改我的事件上已注册的事件。该事件将简单地链接到操作,以便您可以更改操作,但您永远不能同时拥有 2 个。

只是一个想法。还没喝咖啡,所以这可能根本不合适......

于 2012-12-22T14:17:54.633 回答