мы обычно работаем над этим, объявляя наши события следующим образом:
public event EventHandler<FooEventArgs> Foo = delegate { };
это имеет два преимущества. Во-первых, у нас нет проверки на ноль. Во-вторых, мы избегаем проблемы критической секции, которая вездесуща при типичных событиях:
// old, busted code that happens to work most of the time since
// a lot of code never unsubscribes from events
protected virtual void OnFoo(FooEventArgs e)
{
// two threads, first checks for null and succeeds and enters
if (Foo != null) {
// second thread removes event handler now, leaving Foo = null
// first thread resumes and crashes.
Foo(this, e);
}
}
// proper thread-safe code
protected virtual void OnFoo(FooEventArgs e)
{
EventHandler<FooEventArgs> handler = Foo;
if (handler != null)
handler(this, e);
}
Но с автоматической инициализацией Foo пустым делегатом проверка никогда не требуется, и код автоматически поточно-ориентирован, и его легче читать при загрузке:
protected virtual void OnFoo(FooEventArgs e)
{
Foo(this, e); // always good
}
С извинениями перед Пэт Морита в «Карате Кид»: «Лучший способ избежать нуля - это не один».
Что касается того, почему C # не балует вас так сильно, как VB. Хотя ключевое слово события скрывает большинство деталей реализации многоадресных делегатов , оно обеспечивает более точное управление, чем VB.