C++ / CLI позволяет Вам переопределять raise
в пользовательские обработчики событий , таким образом, Вы не должны тестировать на null
или копия при генерировании события. Конечно, в Вашем пользовательском raise
все еще необходимо сделать это.
Пример, адаптированный из MSDN к правильности:
public delegate void f(int);
public ref struct E {
f ^ _E;
public:
void handler(int i) {
System::Console::WriteLine(i);
}
E() {
_E = nullptr;
}
event f^ Event {
void add(f ^ d) {
_E += d;
}
void remove(f ^ d) {
_E -= d;
}
void raise(int i) {
f^ tmp = _E;
if (tmp) {
tmp->Invoke(i);
}
}
}
static void Go() {
E^ pE = gcnew E;
pE->Event += gcnew f(pE, &E::handler);
pE->Event(17);
}
};
int main() {
E::Go();
}
Это еще не вся история! Обычно не стоит беспокоиться об обработчиках нулевых событий в C++/CLI. Код для этих проверок сгенерирован для вас. Рассмотрим следующий тривиальный класс C++/CLI.
public ref class MyClass
{
public:
event System::EventHandler ^ MyEvent;
};
Если скомпилировать этот класс и разобрать его с помощью Рефлектора, то получим следующий код на языке c#.
public class MyClass
{
// Fields
private EventHandler <backing_store>MyEvent;
// Events
public event EventHandler MyEvent
{
[MethodImpl(MethodImplOptions.Synchronized)] add
{
this.<backing_store>MyEvent = (EventHandler) Delegate.Combine(this.<backing_store>MyEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)] remove
{
this.<backing_store>MyEvent = (EventHandler) Delegate.Remove(this.<backing_store>MyEvent, value);
}
raise
{
EventHandler <tmp> = null;
<tmp> = this.<backing_store>MyEvent;
if (<tmp> != null)
{
<tmp>(value0, value1);
}
}
}
}
Обычные проверки выполняются в методе raise. Если только вы действительно не хотите пользовательского поведения, то вы должны чувствовать себя комфортно, объявляя свое событие как в вышеуказанном классе, и поднимая его, не опасаясь нулевого обработчика.