我想知道从C++/CLI引发事件的正确方法是什么.在C#中,我应首先制作处理程序的副本,检查它是否为空,然后调用它.C++/CLI有类似的做法吗?
这不是全部故事!您通常不必担心C++/CLI中的空事件处理程序.这些检查的代码是为您生成的.考虑以下简单的C++/CLI类.
public ref class MyClass { public: event System::EventHandler ^ MyEvent; };
如果您编译此类,并使用Reflector对其进行反汇编,则会获得以下c#代码.
public class MyClass { // Fields private EventHandlerMyEvent; // Events public event EventHandler MyEvent { [MethodImpl(MethodImplOptions.Synchronized)] add { this. MyEvent = (EventHandler) Delegate.Combine(this. MyEvent, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { this. MyEvent = (EventHandler) Delegate.Remove(this. MyEvent, value); } raise { EventHandler = null; = this. MyEvent; if ( != null) { (value0, value1); } } } }
通常的检查是在raise方法中完成的.除非你真的想要自定义行为,否则你应该觉得在上面的类中声明你的事件并且不必担心空处理程序就可以提高它.
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(); }
如果你的问题是加注不是私有的,那么明确地实现它就像文档说:
http://msdn.microsoft.com/en-us/library/5f3csfsa.aspx
综上所述:
如果您只使用event关键字,则会创建一个"普通"事件.编译器为您生成add/remove/raise和委托成员.生成的raise函数(如文档所述)检查nullptr.这里记录了一些微不足道的事件:
http://msdn.microsoft.com/en-us/library/4b612y2s.aspx
如果您想要"更多控制",例如将raise设置为 private,则必须显式实现链接中显示的成员.您必须为委托类型显式声明数据成员.然后使用event关键字声明与事件相关的成员,如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
罗嗦,但确实如此.
-reilly.