2009-01-20 23 views

Respuesta

16

C++/CLI le permite anular raise en controladores custom event, por lo que no tiene que comprobar null o copiar cuando se produce un evento. Por supuesto, dentro de su medida personalizada raise usted todavía tiene que hacer esto.

ejemplo, una adaptación de la MSDN para la corrección:

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(); 
} 
28

Esto no es toda la historia! Por lo general, no tiene que preocuparse por los controladores de eventos nulos en C++/CLI. El código para estas verificaciones se genera para usted. Considere la siguiente clase trivial de C++/CLI.

public ref class MyClass 
{ 
public: 
    event System::EventHandler^MyEvent; 
}; 

Si compila esta clase, y desmontar usando Reflector, se obtiene el siguiente código 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); 
      } 
     } 
    } 
} 

Las comprobaciones habituales se realizan en el método de elevación. A menos que realmente desee un comportamiento personalizado, debe sentirse cómodo declarando su evento como en la clase anterior y criándolo sin temor a un controlador nulo.

+0

Mi problema con este enfoque es que el método "subir" no es privado (como en C#) y se muestra en el intellisense. –

+1

@Filip: Así que ve con un evento personalizado y pon 'privado:' al frente. –

7

Si el problema es que aumento no es privado, a continuación, poner en práctica de forma explícita al igual que los documentos dicen:

http://msdn.microsoft.com/en-us/library/5f3csfsa.aspx

En resumen:

Si usted sólo tiene que utilizar el evento palabra clave, crea un evento "trivial". El compilador genera añadir/eliminar/aumento y el miembro delegado para usted. El aumento generada función (como dicen los documentos) comprueba si el nullptr. eventos triviales están documentados aquí:

http://msdn.microsoft.com/en-us/library/4b612y2s.aspx

Si desea "más control", por ejemplo para hacer aumento privado, entonces usted tiene que poner en práctica de manera explícita los miembros como se muestra en el enlace. Debe declarar explícitamente un miembro de datos para el tipo de delegado. A continuación, se utiliza el evento palabra clave para declarar los miembros relacionados con el evento, como en el ejemplo de Microsoft:

// event keyword introduces the scope wherein I'm defining the required methods 
// "f" is my delegate type 
// "Event" is the unrealistic name of the event itself 
event f^ Event 
{ 
     // add is public (because the event block is public) 
     // "_E" is the private delegate data member of type "f" 
     void add(f^d) { _E += d; } 

    // making remove private 
    private: 
     void remove(f^d) { _E -= d; } 

    // making raise protected 
    protected: 
     void raise(int i) 
     { 
     // check for nullptr 
     if (_E) 
     { 
      _E->Invoke(i); 
     } 
     } 
}// end event block 

prolija, pero no lo es.

-reilly.

Cuestiones relacionadas