2

コンストラクターを介してオプションのデリゲートを受け取る関数をリファクタリングしています。クラス内でイベントがトリガーされると、デリゲートが実行されます。デリゲートが渡されない場合は、代わりにローカルのデフォルト関数が使用されます。

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 を使用した場合)。デリゲートから読み取り専用を削除することもできますが、実際には読み取り専用であるため、優れたソリューションとは思えません。

任意の考えをいただければ幸いです。

4

2 に答える 2

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

于 2016-12-09T13:16:25.383 に答える
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であるかどうかを確認し、そうであれば に設定_onEventTwoDefaultEventTwoます。

誰もが縮小されたコンストラクターを使用するのを避けるには、単に make it 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();
}
于 2016-12-09T13:18:27.587 に答える