【发布时间】:2010-10-02 13:05:13
【问题描述】:
我想知道从 C++/CLI 引发事件的正确方法是什么。在 C# 中一个 should first make a copy of the handler, check if it's not null, and then call it。 C++/CLI 有类似的做法吗?
【问题讨论】:
我想知道从 C++/CLI 引发事件的正确方法是什么。在 C# 中一个 should first make a copy of the handler, check if it's not null, and then call it。 C++/CLI 有类似的做法吗?
【问题讨论】:
C++/CLI 允许您在 custom event 处理程序中覆盖 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;
};
如果你编译这个类,然后用Reflector反汇编它,你会得到下面的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 方法中进行的。除非您真的想要自定义行为,否则您应该可以轻松地在上述类中声明您的事件,并在不担心 null 处理程序的情况下引发它。
【讨论】:
private: 放在前面。
如果您的问题是 raise 不是私有的,那么就像文档说的那样明确地实现它:
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 设为私有,那么您必须显式实现链接中显示的成员。您必须显式声明委托类型的数据成员。然后您使用 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
啰嗦,但就是这样。
-赖利。
【讨论】: