Ответ 1
Ключевое слово события создает аксессуар для частного объекта делегата. То же самое, что и свойство, оно ограничивает доступ к частному полю. Сбой кода вашего кода с аналогичной ошибкой при использовании свойства вместо события:
class ClassA {
public int Property { get; set; }
}
class ClassB {
public ClassB() {
ClassA a = new ClassA();
ClassC c = new ClassC();
c.setValue(ref a.Property); // CS0206
}
}
class ClassC {
public void setValue(ref int value) {
value = 42;
}
}
Теперь легче видеть, компилятор не может гарантировать, что метод setValue() использует свойство setter. Также он не мог знать, что аргумент "значение" является свойством с установщиком или простым полем.
Это менее понятно для события, потому что на работе так много синтаксического сахара. Это объявление
public event EventHandler SomeEvent;
действительно генерирует этот код:
private EventHandler _SomeEvent;
public event SomeEvent {
add { _SomeEvent += new EventHandler(value); }
remove { _SomeEvent -= new EventHandler(value); }
}
Аксессоры добавления и удаления эквивалентны get и set accessors свойства, они не позволяют коду взаимодействовать с частным полем _SomeEvent. По соглашению, add accessor вызывается, когда вы используете + =, remove вызывается с помощью = =. Сравните это с предыдущим примером, который я дал для свойства. Такая же проблема, вы не можете использовать ключевое слово ref, и ClassC.addListener() не имеет никакого способа узнать, что обработчик на самом деле является событием вместо объекта-делегата. Если вместо этого компилятор передаст _SomeEvent, точка использования аксессуаров будет потеряна.
Вы можете реструктурировать код для решения этой проблемы:
class ClassC {
public EventHandler getListener() {
return new EventHandler(onEvent);
}
private void onEvent(object sender, EventArgs e) { }
}
...
a.SomeEvent += c.getListener();
Последнее замечание: симметрия между событием и свойством немного потеряна, компилятор С# автоматически генерирует add/remove accessors, если вы не пишете их явно. Он не делает этого для собственности. Это сделало бы автоматические свойства намного проще:
property int Property;
Но это потребовало бы добавления нового ключевого слова на язык, что-то, что команда С# действительно не любит. Другие языки, такие как VB.NET и С++/CLI, имеют это ключевое слово.