14

次の 3 つの方法があるとします。

void Foo(MemoryStream v) {Console.WriteLine ("MemoryStream");}
void Foo(Stream v)       {Console.WriteLine ("Stream");}
void Foo(object v)       {Console.WriteLine ("object");}

Fooオープン ジェネリック型の最初のパラメーターを渡すメソッドを呼び出します。

void Bar<T>()
{
    Foo(default(T)); //just to show the scenario
    //default(T) or new T() doesn't make a difference, null is irrelevant here
}

オーバーロードを呼び出したいMemoryStreamので、ジェネリック型のメソッドBarMemoryStream次のように閉じます。

Bar<MemoryStream>();

しかし、objectオーバーロードが呼び出されます。Foo signature に一般的な制約を追加するとwhere T : StreamStreamバージョンが呼び出されます。

MemoryStreamオープンジェネリック型に基づいて、メソッド呼び出しをオーバーロードにディスパッチする方法はありTますか?

Delegate.CreateDelegateまたは他の Reflection APIを使用したくありません。C#言語の手段で。おそらく、言語自体に何かが欠けているのでしょう。

閉じたジェネリック型として値型を使用し、静的メソッドを使用して、このシナリオを試しました。

4

6 に答える 6

9

これは、動的バインディングを使用してのみ行うことができます。たとえば、次のようになります。

void Bar<T>(T value)
{
    dynamic parameter = value;
    Foo(parameter); 
}

動的ディスパッチは、実際のランタイム オブジェクトの実際のランタイム タイプを使用してメソッド ディスパッチを行うため、オブジェクトが必要であることに注意してください。値がの場合null、これは機能しません。

于 2013-10-21T11:02:58.103 に答える
4

おそらく次のようなものです:

void Bar<T>()
{
   if(typeof(T) == typeof(Stream))
      Foo(default(T) as Stream);  //just to show the scenario
}
于 2013-10-21T10:32:41.567 に答える
2

これは「きれいな」答えではありません (実際、これはジェネリックの意図を覆すようなものであるため、言語内できれいな答えを見つけるのは困難です) が、おそらく辞書を介してオーバーロード ルックアップをコーディングできます。

static readonly Dictionary<Type, Action<object>> overloads
    = new Dictionary<Type, Action<object>> {
        {typeof(Stream), o => Foo((Stream)o)},
        {typeof(MemoryStream), o => Foo((MemoryStream)o)}
    };
public static void Bar<T>() {
    Action<object> overload;
    if (overloads.TryGetValue(typeof(T), out overload)) {
        overload(default(T));
    } else {
        Foo((object)default(T));
    }
}

これは良くないので、お勧めしません。メンテナンスを容易にするために、overloads人口を静的コンストラクター/型初期化子に移動し、リフレクションを介してデータを入力することができます。また、これは正確な T場合にのみ機能することに注意してください-誰かが予期しないタイプを使用した場合(Bar<NetworkStream>たとえば)、機能しません-おそらくベースタイプをループすることはできます(しかし、それでも、インターフェースなどの優れたサポートはありません) )。

このアプローチは、すべてを考慮して、推奨するものはあまりありません。おそらく、問題全体に別の角度からアプローチすることをお勧めします(つまり、これを行う必要がなくなります)。

于 2013-10-21T10:50:21.497 に答える
0

default(T) は、型 T が参照型の場合は常に null を返し、T が数値型の場合はゼロを返します。

したがって、いつでも、オーバーロードされたバージョンの Foo メソッドを呼び出すことができるオブジェクトを返しません。

したがって、これを行うことはできません。オーバーロードされたメソッドを呼び出す他の方法を見つける必要があります。

于 2013-10-21T10:58:09.793 に答える
0

私は同じ問題を抱えていました.私が知っていたユニークな解決策は、null. 次に、コンパイル時に正しい型を取得し、コンパイラは呼び出す正しいオーバーロードを認識します。この「実行時ポリモーフィズム」を実現する別の方法を見つけることができませんでした。

ディクショナリやスイッチのようなソリューション (Marc が指摘したように保守性が低い) の使用を避けるには、呼び出すだけでMethod((dynamic) o)、DLR は実行時の型に応じて正しいオーバーロード メソッドを呼び出します。

覚えておいてください:

1) 可能な限り最上位のタイプでデフォルトのオーバーロードを提供します。

2) 実行時の型の解決中のあいまいさに注意してください (つまり、2 つの独立したインターフェースと、両方を使用する 1 つの実装)。

3)nullケースを処理します。

詳細については、こちらをご覧ください。

私が助けたことを願っています。

于 2015-07-23T19:08:23.133 に答える