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

时间:2009-01-20 19:46:22

标签: events c++-cli raise

我想知道从C ++ / CLI引发事件的正确方法是什么。在C#one s hould first make a copy of the handler, check if it's not null, and then call it中。 C ++ / CLI是否有类似的做法?

3 个答案:

答案 0 :(得分:28)

这不是全部故事!您通常不必担心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方法中进行检查。除非你真的想要自定义行为,否则你应该觉得在上面的类中声明你的事件并且不必担心空处理程序就可以提升它。

答案 1 :(得分:18)

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

答案 2 :(得分:7)

如果您的问题是 raise 不是私有的,那么就像文档说的那样明确地实现它:

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

总结:

如果您只使用 事件 关键字,则会创建“琐碎”事件。编译器生成 添加 / 删除 / 提升 和你的代表成员。生成的 引发 功能(如文档所述)检查 nullptr 。这里记录了一些微不足道的事件:

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

如果您想要“更多控制权”,例如将 引发 设为私​​有,那么您必须明确实现链接中显示的成员。您必须为委托类型显式声明数据成员。然后使用 事件 关键字声明与事件相关的成员,如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。