15

C++/CLI からイベントを発生させる適切な方法は何だろうと思っていました。C# では、最初にハンドラーのコピーを作成し、それが null でないかどうかを確認してから、それを呼び出す必要があります。C++/CLI にも同様の方法はありますか?

4

3 に答える 3

30

これがすべてではありません!通常、C++/CLI の null イベント ハンドラーについて心配する必要はありません。これらのチェックのコードが生成されます。次の単純な 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 メソッドで通常のチェックが行われています。カスタムの動作が本当に必要でない限り、上記のクラスのようにイベントを宣言し、null ハンドラーを恐れることなくイベントを発生させることができます。

于 2010-01-06T17:13:43.777 に答える
19

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();
}
于 2009-01-20T19:55:26.007 に答える
7

レイズがプライベートではないという問題がある場合は、ドキュメントのように明示的に実装します。

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

要約すれば:

eventキーワードだけを使用すると、「些細な」イベントが作成されます。コンパイラはadd / remove / raiseとデリゲート メンバーを生成します。生成されたraise関数 (ドキュメントが言うように) は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

冗長ですが、そこにあります。

-ライリー。

于 2011-03-04T11:32:14.133 に答える