web-dev-qa-db-ja.com

C#-デリゲートを「オーバーロード」するにはどうすればよいですか?

最初に、私はいくつかのフォーラムとMSDNのヘルプを読んでいましたが、すべての人がデリゲートをオーバーロードすることはできないと言っています。

今、私はこのようなものが欲しいです:

public delegate void OneDelegate();
public delegate void OneDelegate(params object[] a);

public void DoNothing(params object[] a) {}
public void DoSomething() { /* do something */ }

private OneDelegate someFunction;

someFunction = new OneDelegate(DoSomething);
someFunction = new OneDelegate(DoNothing);

したがって、ご存知のように、OneDelegateは最初のもののみを参照し、2番目のものは参照しないため、これを行うことはできません。しかし、これを行う方法はありますか?またはそのようなもの?

PS1:1つまたは2つだけでなく、OneDelegate宣言をいくつでも使用したい。

これが可能だったと少し想像してみてください。オーバーロードされたデリゲートを持つことができると仮定します。

_public delegate void OneDelegate(int i);
public delegate void OneDelegate(string s);
_

ここで、このタイプの変数を宣言してから、それに関数を割り当てると想像してください。次に例を示します。

_OneDelegate myDelegate = StringMethod;
_

ここで、StringMethodは次のように宣言されます。

_public void StringMethod(string s) { Console.WriteLine(s); }
_

ここで、myDelegateを他のコードに渡すと、そのコードは次のことを行います。

_myDelegate(47);
_

この場合、何が起こると思いますか?ランタイムは整数の引数を使用してStringMethod()をどのように呼び出すことができますか?

パラメータの任意のセットを取ることができるデリゲートが本当に必要な場合、唯一のオプションは_params object[]_配列を持つデリゲートを持つことです。

_public delegate void OneDelegate(params object[] parameters);
_

ただし、次に、実際に任意のオブジェクト配列を処理できる関数を割り当てる必要があります。次に例を示します。

_public void MyMethod(params object[] parameters)
{
    if (parameters == null || parameters.Length == 0)
        throw new ArgumentException("No parameters specified.");
    if (parameters.Length > 1)
        throw new ArgumentException("Too many parameters specified.");

    if (parameters[0] is int)
        IntMethod((int) parameters[0]);
    else if (parameters[0] is string)
        StringMethod((string) parameters[0]);
    else
        throw new ArgumentException("Unsupported parameter type.");
}
_

ご覧のとおり、これはすぐに面倒になります。したがって、そのような代理人が必要な場合は、おそらく建築設計のどこかで間違いを犯していることをお伝えします。実装を進める前に、この欠陥を特定して設計を修正してください。そうしないと、コードの保守性が低下します。

37
Timwi

アクション クラスは「これを行います」。これはテンプレートを使用したデリゲートであるため、次のようなデリゲートを持つことができます。

public delegate void D<T>(params T[] arg);

func() {
    D<object> d1;
}

これはおそらく、取得しようとしているものと同じくらい近いです。つまり、パラメータとしてテンプレートタイプが必要です。

編集:コメントに基づいて、デリゲートを別の関数に渡した後だと思います。引数を渡すことによってもそれを達成することができます。残念ながら、fireへのparamsパラメータを使用せずにこれを行うことはできません。

public void bar() {
    D<string> d = ...;
    fire(d, "first", "second");
    fire(d); // also works
}

public void fire<T>(D<T> f, params T[] args) {
    f(args);
}
7
Patrick