2016-04-28 4 views
2

他のクラスからイベントを呼び出すことは事実上意味をなさないと思います。イベントが別のクラスから設定されているかどうかを検出

しかし、いくつかの最適化を行うために、イベントが設定されていないとパフォーマンスを向上させることができました。

悲しいことにC#が、私はこの

public class A 
{ 
    public event Action Event; 

    public bool IsEventSet { return Event != null; } 
} 

main 
{ 
    var a = new A(); 
    var isSet = a.Event == null; //why is this not allowed! I can not understand 
    isSet = a.IsEventSet; //this seems like a hack to me! 
} 

を行うことができていない私は、私は十分に明確だ願っていますし、この

理由があり、このための理由がありますか?

ありがとうございます!

+0

@phoog、私は –

+0

ああ、大丈夫、あなたの編集後に、それはより多くを作ることを編集し、私は十分に明確だと思いましたセンス。私はこれが重複していると確信していますが、答えを探す時間がありません。私が正しく思い出した場合、Eric Lippertは数年前にC#チームが自分が選んだイベントパターンを選んだ理由を議論する長い答えを書きました。 – phoog

+0

私はそれを見て、私はそれを見つけることができませんでした –

答えて

4
var isSet = a.Event == null; //why is this not allowed! I can not understand 

なぜ許可されていませんか?それはeventであるため、delegateではありません。

eventは、制約付きのデリゲートに過ぎません。

イベントのような代理人を扱うことができるようになるまで、私は数年間C#をコーディングしていました。具体的には、任意の数のサブスクライバを1つのデリゲートにアタッチおよびデタッチできます。

次のコードは、これを示しています。

using System; 

public class A 
{ 
    public event Action Event; 

    // You could just use System.Action, but I want the example to be clear 
    public delegate void HandlerDelegateType(); 

    public HandlerDelegateType PublicDelegate; 


    public void Fire() 
    { 
     if(PublicDelegate != null) 
     { 
      PublicDelegate(); 
     } 
    } 
} 

public static class MainClass 
{ 
    public static int Main(string[] args) 
    { 
     var a = new A(); 

     if(a.PublicDelegate == null) 
     { 
      Console.WriteLine("a.PublicDelegate is null"); 
     } 

     a.PublicDelegate +=() => { Console.WriteLine("First handler fired!"); }; 
     a.PublicDelegate +=() => { Console.WriteLine("Second handler fired!"); }; 


     a.Fire(); 

     if(a.PublicDelegate != null) 
     { 
      Console.WriteLine("a.PublicDelegate is not null"); 
     } 


     return 0; 
    } 
} 

ログ出力が

a.PublicDelegateが解雇

ヌルまずハンドラです!

2番目のハンドラが起動しました!

a.PublicDelegateはeventキーワードを使用することにより

nullでなく、明示的にそれを使用することができる方法を制限しています。

メンバーへのアクセス方法を制限することは、オブジェクト指向設計の重要な側面です。これは、デザイナーに、あなたのクラスがどのように使われるかについて意見を述べることができます。 C#はあなたにこの機能を提供しますが、喜んでそれに同意できず、イベントではなくデリゲートを公開します。


ここで、「制約付きのデリゲート」という表現は単純すぎることを認めます。 そのようにあなたが実際に、基本となるデリゲートへのパブリックインタフェースとしてイベントを公開することができます:ここであなたを助けて糖衣構文の全体の多くがありますので、C#は、あなたがこれを行うことはできません

private HandlerDelegateType _privateDelegate; 

public event HandlerDelegateType PublicEvent 
{ 
    add 
    { 
     _privateDelegate += value; 

    } 
    remove 
    { 
     _privateDelegate-= value; 
     if(_privateDelegate == null) 
     { 
      // Can perform some other action here 
      // For example, unsubscribe from a second event source 
     } 
    } 
} 
+0

イベントフォームにハンドラが付いていれば別のクラス、私はこれについて実際的な方法はないと思う。 –

+0

@ bto.rdz - 私の意見:あなたの 'a.IsEventSet'ソリューションが最高の解決策です。 –

+0

あなたの明確な説明をありがとうございました。 –

1

理由があります。 C#のイベントは実際にはプロパティと密接に関連しています。通常、あなたが使用する短いフォームはオートプロパティのようなものです。あなたは実際にコンパイラにあなたのために多くの仕事をさせています。

おそらく、コンパイラが生成するイベントの完全な宣言を確認するのに役立ちます。私が下に持つものは、コンパイラが生成するものとおおよそ同等です。

public class A 
{ 
    public event Action Event 
    { 
     add 
     { 
      mEventBackingField = (Action) Delegate.Combine(mEventBackingField, value); 
     } 
     remove 
     { 
      mEventBackingField = (Action) Delegate.Remove(mEventBackingField, value); 
     } 
    } 

    private Action mEventBackingField; 
} 

私は、コンパイラは、スレッドの安全性のためにそこに投げいくつかの他のジャンクを残してきたが、これは、あなたがpublic event Action Event;を書くときに何が起こっているかの一般的な要点です。クラス内でEventを参照すると、コンパイラは基本的にそれをそのイベントのバッキングフィールドへの参照で置き換えます。これにより、ヌルチェックを行い、クラス内からイベントを呼び出すことができます。

クラス外からは、実際に表示されるのは、イベントのaddremoveのメソッドだけです。基本的なデリゲートを実際に見る方法はありません。これは良いことです。

なぜですか?あなたがクラス外の基盤となるデリゲートの価値を得ることが許されていれば、クラス外からイベントを呼び出すことができます!どこにいても誰でもそのイベントを知り、登録された代表者を呼び出すことができます。それはメンテナンスの悪夢だろう。

しかし、実際にそのようなことを起こしたいのであればどうしますか?さて、あなたがイベントをしたくないという場合には、あなたが財産をしたい:私は知っている

public class A 
{ 
    public Action Event { get; set; } 
}