Есть ли в C ++ / CLI слушатели? - PullRequest
5 голосов
/ 07 декабря 2011

В C # я могу проверить, есть ли событие у слушателей:

C # Пример:

public static event EventHandler OnClick;

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

В C ++ / CLI проверка на отсутствие события не обязательна.

C ++ / CLI Пример:

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

OnClick (sender, args);

НО, в проекте, над которым я работаю, я не хочу создавать объект MyEventArgs, если нет слушателей.

Как узнать, есть ли у OnClick какие-либо слушатели в C ++?

Ответы [ 2 ]

2 голосов
/ 02 августа 2014

Основываясь на обсуждении комментариев с @BenVoigt об исходном ответе @ svick и новой статье MSDN о событиях C ++ / CLI , я создал минимальный пример того, как сделать это правильно. Этот код компилируется и выполняется в шаблоне проекта Visual Studio 2013 CLR с ориентацией на .NET 4.5. Я не тестировал другие среды выполнения и цели, но он использует только базовые компоненты .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();
}
2 голосов
/ 07 декабря 2011

Кажется, вы не можете проверить это с помощью "тривиальных событий", как вы использовали, потому что у вас нет прямого доступа к базовому полю (как с автоматически реализуемыми свойствами в C #).

Если вы хотите сделать это, вы можете явно указать методы доступа к событию и поле поддержки. См. Как: определить методы доступа к событиям о том, как именно это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...