关于C ++ CLI:从C ++ / CLI引发事件的正确方法?

Proper way of raising events from C++/CLI?

我想知道从C ++ / CLI引发事件的正确方法是什么。 在C#中,应该首先复制处理程序,检查其是否不为null,然后调用它。 C ++ / CLI是否有类似的做法?


这还不是全部!您通常不必担心C ++ / CLI中的空事件处理程序。这些检查的代码已为您生成。考虑下面的普通C ++ / CLI类。

1
2
3
4
5
public ref class MyClass
{
public:
    event System::EventHandler ^ MyEvent;
};

如果编译此类,然后使用Reflector对其进行反汇编,则将获得以下c#代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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处理程序的情况下进行声明。


C ++ / CLI允许您在自定义事件处理程序中覆盖raise,因此在引发事件时不必测试null或复制。当然,在自定义raise中,您仍然必须这样做。

为了更正,示例从MSDN改编而成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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/zh-CN/library/5f3csfsa.aspx

综上所述:

如果仅使用event关键字,则会创建一个"琐碎的"事件。编译器会为您生成添加/删除/提升和委托成员。生成的raise函数(如文档所说)检查nullptr。琐事记录在这里:

http://msdn.microsoft.com/zh-CN/library/4b612y2s.aspx

例如,如果您想"更多控制权"以将抬高设置为私有,则必须显式实现成员,如链接中所示。您必须为委托类型显式声明一个数据成员。然后,使用event关键字声明与事件相关的成员,如Microsoft示例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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

罗y的,但确实如此。

-赖利