【问题标题】:.NET event raising and NullObject pattern.NET 事件引发和 NullObject 模式
【发布时间】:2012-11-17 17:16:08
【问题描述】:

我们可以通过两种方式引发事件:

public event EventHandler MyEvent;

private void DoSomething()
{
    ...
    var handler = MyEvent;
    if (handler != null)
        handler(this,EventArgs.Empty);
}

public event EventHandler MyEvent = (o,e) => {} ;

private void DoSomething()
{
    ...
    MyEvent(this, EventArgs.Empty);
}

我更喜欢最后一个。它更短。
我的同事坚持第一个变体。

第一个比第二个有优势吗?

【问题讨论】:

  • 你至少可以将第一个简化为if (this.MyEvent != null) this.MyEvent(this, EventArgs.Empty);
  • @JonB:错误;这不是线程安全的。
  • 你将如何防止类将事件设置为空?
  • @Jon 不,你不应该。这可能会导致竞争条件,请参阅Eric Lippert's blog
  • 如果某些代码将事件设置为 null,则第二个变体引发 null 异常。

标签: c# .net events design-patterns


【解决方案1】:

C# 6 更新

在 C# 6 中,您只需像这样使用空条件运算符:

PropertyChanged?.Invoke(this, args);

这是recommended by the Roslyn wiki

原答案

Eric Lippert 有 a great blog post on Events and Races,如果你还没有的话,你应该阅读它。

第一个选项可能被认为比第二个更安全,因为事件可能被设置为 null。有人可能会不小心修改类。此外,如果您反序列化实例,则第二种方法将不起作用(取决于您使用的序列化机制)。

我有时会使用辅助方法来引发事件

static class Raiser
{
    public static void Raise<T>(this EventHandler<T> evnt, object sender, T args)
        where T : EventArgs
    {
        if (evnt != null)
        {
            evnt(sender, args);
        }
    }
}

class SomeClass
{
    public event EventHandler<EventArgs> MyEvent;

    private void DoSomething()
    {
        MyEvent.Raise(this, EventArgs.Empty);
    }
}

【讨论】:

  • 两全其美和很好地使用扩展方法,得到我的橙色箭头。
  • 很好的辅助方法。谢谢!
  • 我同意你的论点,但我对“粗心的修改”感兴趣。这是否意味着我应该检查方法中的任何变量,这些变量可能会在代码中的其他地方意外更改?我认为这是出于此目的的代码合同的不变量。
  • 好吧,我不认为粗心的修改是支持选项 1 而不是选项 2 的理由,但你的同事可能:)
猜你喜欢
  • 2020-11-07
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多