3

C#で、真のシングルキャストデリゲートをどのように作成しますか。つまり、呼び出しリスト内の1つの(そして1つだけの)メソッドを参照できるデリゲートインスタンスであり、イベント(多数のサブスクライバーが存在する可能性がある)ではなく、コールバック(単一のサブスクライバーの場合)として使用されます。

フレームワークには、System.DelegateクラスとSystem.MulticastDelegateクラスがあり、System.Delegateはシングルキャストであり、System.Multicastデリゲートはマルチキャスト機能を追加しているという誤った印象を与えます。しかし、System.Delegate http://msdn.microsoft.com/en-us/library/system.delegate.aspxのMSDNドキュメントには、System.Delegateが実際にはマルチキャストであることが示されています...

「デリゲートの呼び出しリストは、リストの各要素がデリゲートによって表されるメソッドの1つだけを呼び出す順序付けられたデリゲートのセットです。」

...一方、System.MulticastDelegateのドキュメントでは、System.MulticastDelegateが提供する追加の動作については実際には説明されていません。

この分野の公式ドキュメントはかなり紛らわしいですが、明確なことの1つは、エンドユーザーがSystem.DelegateまたはSystem.MulticastDelegateのどちらからも派生できないことです。それで、単一のコールバックへの参照を格納するための変数として使用できる真のシングルキャストデリゲートを作成するためのフレームワークによってサポートされる方法はありますか?

@dtb。シングルキャストデリゲートを使用できる場合は、ランタイムチェックの必要がなくなります。もちろん、間違ったハンドラーが割り当てられるなど、アプリケーションロジックが他の方法で失敗する可能性があることは事実ですが、少なくともシングルキャストデリゲートを使用する場合、1つだけを期待する複数のハンドラーが存在するという問題は、単純に1つの問題です。存在することはできないため、チェックすることが1つ少なくなり、ユニットテストが簡単になり、デザインがよりエレガントになります。また、戻り値を持つメソッドのデリゲートの呼び出しリストに複数のハンドラーがある場合、最初のハンドラーではなく、リストの最後のハンドラーによって返される値が呼び出し元に返されます。

4

2 に答える 2

3

イベントを含む「シングルキャスト」デリゲートが本当に必要な場合は、そのイベントに独自の追加/削除メソッドを実装してみませんか?

の「問題」はDelegate派生MulticastDelegateクラスであるため、誰かがMulticastDelegateオブジェクトをDelegate変数に割り当てると、常に。が発生しMulticastDelegateます。

たとえば、デフォルトのevent実装を次のように簡略化できます。

private ChangedEventHandler _changed;
public event ChangedEventHandler Changed
{
   add
   {
      _changed += value;
   }
   remove
   {
      _changed -= value;
   }
}

次に、イベントの実装を次のように変更しましょう。

private ChangedEventHandler _changed;
public event ChangedEventHandler Changed
{
   add
   {
      _changed = value; // Do NOT combine delegates
   }
   remove
   {
      _changed -= value;
   }
}

これで、(ほぼ)シングルキャストデリゲートになります。イベント構文のため、ユーザーはマルチキャストデリゲートを直接割り当てることができず、最後に割り当てられたデリゲートのみが保存されます。ユーザーが本当に悪意のある場合は、を作成して、MulticastDelegateそのデリゲートをイベントハンドラーに追加できます。これを本当に防ぐ必要がある場合は、このチェックをaddメソッドに追加できます。

if (value.GetInvocationList().Length > 1)
    throw new ArgumentException("MulticastDelegates are not allowed here.");
于 2012-09-06T12:55:42.567 に答える
1

デリゲートを使用するよりも少し厄介ですが、1つのアプローチは、必要なメソッドを使用してコールバックインターフェイスを渡すことです。メソッドの実装は1つだけであるため、登録できるコールバックは1つだけです。

public interface IDoSomething
{
    void DoSomething();
}

public sealed class MyClass
{
    private IDoSomething _doer;

    //We use a Set method rather than a property to prevent other classes from accessing the callback
    //Another common (and generally better) pattern is to pass the instance into the constructor
    public void SetSomethingDoer(IDoSomething doer)
    {
        _doer = doer;
    }

    //Other code can now access _doer to call back the method
}

これには、複数のコールバックメソッドをグループ化できるという副次的な利点があります。これは、単一のコールバックハンドラーを保証しようとしている場合に、多くの場合意味があります。

于 2012-09-06T15:25:20.593 に答える