2016-12-09 9 views
2

私はコンストラクタを介してオプションのデリゲートを受け取る関数をリファクタリングしています。デリゲートは、クラス内でイベントがトリガーされたときに実行されます。デリゲートは、その後渡されていない場合はローカルのデフォルトの機能が代わりに使用されています。私は、デフォルト値を(これは非常に望ましいだろうオーバーロードをパブリックインタフェースである)を除去するために探していますが、これは生産されてC#コンストラクタで任意の代理人を処理する最善の方法は何ですか?

public class Foo 
{ 
    int _memberVariable; 
    readonly Action _onEventOne; 
    readonly Action _onEventTwo; 

    public Foo(Action onEventOne, Action onEventTwo = null) 
    { 
     _memberVariable = 0; 

     _onEventOne = onEventOne; 
     _onEventTwo = onEventTwo ?? DefaultEventTwo; 

     _onEventOne(); 
    } 

    private void DefaultEventTwo() 
    { 
     ++_memberVariable; 
    } 
} 

私がしなければインタフェースを変更したくないからです。私は、コンストラクタチェーンを使用したい理想の世界では

public Foo(Action onEventOne) : this(onEventOne, DefaultEventTwo) 
{ 
    //CS0120 An object reference is required for the non-static field, method, or property 'Foo.DefaultEventTwo() 
} 

(これはこれだけではなかった場合、私が使用するソリューションの種類の例を挙げ、動作しない理由を私は理解してコンストラクタ)。

デリゲートは読み取り専用なので、共有初期化タイプの関数でデリゲートを設定することはできません。

nullを渡してメインのコンストラクタでキャッチするようなケースを処理するより良い方法はありますか?それは非常にエレガントな感じではない、私は外の呼び出し元がオーバーロードされたコンストラクタを使用する代わりにnullを使用した場合、理想的に例外としてnullアクションをキャッチすることができるようにしたいと思います。私は代議員から読んだものを取り除くことができましたが、本当に読んでいるだけに、素晴らしい解決策のようには感じられません。

どのような考えにも感謝します。

+1

公共 'フー(アクションonEventOne):この(onEventOne、ヌル)は'だろうどのような他のすべての呼び出しがどこから来たのかを示すのparamで呼び出す「メイン」 - オンとして内部コンストラクタを使用する方法についてpublic static void NoEvent() { // DoNothing() } 'のようなfuncを持っています。次のように扱う: '...、new Action(NoEvent) ' – TripleEEE

+1

そして、(nullではない)デリゲートの代わりに' DefaultEventTwo'を呼び出すと 'null'をチェックします。 – HimBromBeere

答えて

1

私はこの作業を得ることができた唯一の方法は、それが醜い(自分の意見では)働くことであった。

静的メソッドを渡す必要がありますが、その静的メソッドは実際のメソッドを取得するためにこのメソッドへの参照を使用できます。

これは私が思いついたものです。

public Foo(Action onEventOne) : this(onEventOne, self => self.DefaultEventTwo) 
{ 
    //CS0120 An object reference is required for the non-static field, method, or property 'Foo.DefaultEventTwo() 
} 

public Foo(Action onEventOne, Action onEventTwo = null) : this(onEventOne, self => onEventTwo) 
{ } 

// private constructor, just for the sake of getting it working 
private Foo(Action onEventOne, Func<Foo, Action> onEventTwo = null) 
{ 
    _memberVariable = 0; 

    _onEventOne = onEventOne; 
    _onEventTwo = onEventTwo(this); // <-- 

    _onEventOne(); 
} 

self => self.DefaultEventTwoは、アクションを取得する静的関数です。この関数は、onEventTwo(this)の呼び出しでデフォルトのイベントthisインスタンスを取得するために使用されます。

+0

私はこれに本当に素晴らしい解決策がないと思っています。私はほとんどの人が持っていたアイディアを見たいと思っています。これは間違いなく問題に関してはうまくいきますが、余分なオプションのイベントを追加すると少し混乱するようになります(明らかにここのマークではありません。 –

+0

ええ、他の答えと同じように静的にしたり、コンストラクタに移動したりしなければ、望むことをすることはできません。 –

1

私は何かを見逃しましたか?

public class Foo 
{ 
    int _memberVariable; 
    readonly Action _onEventOne; 
    readonly Action _onEventTwo; 

    public Foo(Action onEventOne): this(onEventOne, null) { } 
    public Foo(Action onEventOne, Action onEventTwo) 
    { 
     _memberVariable = 0; 

     _onEventOne = onEventOne; 
     _onEventTwo = onEventTwo ?? DefaultEventTwo; 

     _onEventOne(); 
    } 

    private void DefaultEventTwo() 
    { 
     ++_memberVariable; 
    } 
} 

デフォルト値を削除し、引数が1つしかない新しいコンストラクタを作成するだけで済みます。今最も詳細なコンストラクタ(元のコンストラクタ)では、指定された値がnullであるかどうかを確認し、そうであれば_onEventTwoからDefaultEventTwoに設定します。

誰でも縮小コンストラクタを使用しないようにするには、単にinternalにします。

EDIT:例外処理について。

internal Foo(Action onEventOne): this(onEventOne, null, true) { } 
// public API: NULL not allwoed as param 
public Foo(Action onEventOne, Action onEventTwo) : this(onEventOne, onEventTwo, false) { } 
internal Foo(Action onEventOne, Action onEventTwo, bool internalUse) 
{ 
    _memberVariable = 0; 

    _onEventOne = onEventOne; 
    if(onEventTwo == null) 
    { 
     if(!internalUse) throw new ArgumentNullException("onEventTwo"); 
     else this._onEventTwo = DefaultEventTwo; 
    } 
    _onEventOne(); 
} 
+0

私は2番目の解決策が2つの質問にはるかに優れていると思います(最初の解決策は最初の解決策でしたが、代替案を探しています)。余分な議論を加えることは、私が考えていなかった興味深い考えです(今はとても分かりそうです)。ありがとう! –

関連する問題