C ++ / CLI事件是否有任何侦听器?

时间:2011-12-07 09:35:34

标签: events c++-cli listeners

在C#中,我可以检查一个事件是否有任何监听器:

C#示例:

public static event EventHandler OnClick;

if (OnClick != null)
    OnClick(null, new EventArgs() );

在C ++ / CLI中检查事件是否为null是不必要的。

C ++ / CLI示例:

delegate void ClickDelegate( Object^ sender, MyEventArgs^ e );
event ClickDelegate^ OnClick;

OnClick (sender, args);

但是,在我正在进行的项目中,如果没有侦听器,我不想构造MyEventArgs对象。

如何确定OnClick是否在C ++中有任何侦听器?

2 个答案:

答案 0 :(得分:2)

您似乎无法像使用“平凡事件”一样检查它,因为您无法直接访问基础字段(与C#中的自动实现属性一样)。

如果要执行此操作,可以显式指定事件的访问者方法和支持字段。有关如何做到这一点,请参阅How to: Define Event Accessor Methods

答案 1 :(得分:2)

基于@BenVoigt对@ svick的原始答案和新MSDN article on C++/CLI events的评论讨论,我创建了一个如何正确执行此操作的最小示例。此代码在面向.NET 4.5的Visual Studio 2013 CLR项目模板中编译和运行。我没有测试其他运行时和目标,但它只使用基本的.NET组件。

TL; DR:

  • 将支持字段设为私有
  • 使用System::Threading::Monitor
  • 锁定每次添加,移除和提出通话
  • 使用标准事件处理程序约定:

    void MyEventHandler(Object ^sender, MyEventArgs ^e);
    
  • 使用+=-=除非支持字段为nullptr

我的解决方案:

// compile with: /clr
#include "stdafx.h"

using namespace System;
using System::Threading::Monitor;

public delegate void MyDelegate(Object ^sender, EventArgs ^e);

ref class EventSource {
private:
    MyDelegate ^myEvent;
    Object ^eventLock;

public:
    EventSource()
    {
        eventLock = gcnew Object();
    }

    event MyDelegate^ Event {
        void add(MyDelegate^ handler) {
            Monitor::Enter(eventLock);
            if (myEvent == nullptr)
            {
                myEvent = static_cast<MyDelegate^> (
                            Delegate::Combine(myEvent, handler));
            }
            else
            {
                myEvent += handler;
            }
            Monitor::Exit(eventLock);
        }

        void remove(MyDelegate^ handler) {
            Monitor::Enter(eventLock);
            if (myEvent != nullptr)
            {
                myEvent -= handler;
            }
            Monitor::Exit(eventLock);
        }

        void raise(Object ^sender, EventArgs ^e) {
            Monitor::Enter(eventLock);
            if (myEvent != nullptr)
                myEvent->Invoke(sender, e);
            Monitor::Exit(eventLock);
        }
    }

    void Raise()
    {
        Event(this, EventArgs::Empty);
    }
};

public ref struct EventReceiver {
    void Handler(Object ^sender, EventArgs ^e) {
        Console::WriteLine("In event handler");
    }
};

int main() {
    EventSource ^source = gcnew EventSource;
    EventReceiver ^receiver = gcnew EventReceiver;

    // hook event handler
    source->Event += gcnew MyDelegate(receiver, &EventReceiver::Handler);

    // raise event
    source->Raise();

    // unhook event handler
    source->Event -= gcnew MyDelegate(receiver, &EventReceiver::Handler);

    // raise event, but no handlers
    source->Raise();
}