Правильный способ поднять события из C ++ / CLI? - PullRequest
15 голосов
/ 20 января 2009

Мне было интересно, как правильно вызывать события из C ++ / CLI. В C # один s должен сначала сделать копию обработчика, проверить, не является ли он нулевым, а затем вызвать его . Есть ли подобная практика для C ++ / CLI?

Ответы [ 3 ]

28 голосов
/ 06 января 2010

Это не вся история! Обычно вам не нужно беспокоиться о нулевых обработчиках событий в 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);
            }
        }
    }
}

Обычные проверки выполняются методом рейза. Если вы действительно не хотите нестандартного поведения, вы должны чувствовать себя комфортно, объявляя событие как в предыдущем классе, и поднимая его, не опасаясь нулевого обработчика.

18 голосов
/ 20 января 2009

C ++ / CLI позволяет переопределить 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();
}
7 голосов
/ 04 марта 2011

Если ваша проблема заключается в том, что повышение не является частным, то явным образом реализуйте это, как говорят документы:

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

В итоге:

Если вы просто используете ключевое слово , вы создаете «тривиальное» событие. Компилятор генерирует add / remove / Повышение и член делегата для вас , Сгенерированная функция повышения (как говорят документы) проверяет наличие nullptr . Тривиальные события документированы здесь:

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

Если вы хотите, чтобы «больший контроль», например, сделал повышение приватным, то вы должны явно реализовать членов, как показано в ссылке. Вы должны явно объявить член данных для типа делегата. Затем вы используете ключевое слово 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

Глупо, но вот оно.

-reilly.

...