4

このような状況に遭遇したとき、私は驚きました。最善の解決策が何であるかわからないことに気づきました。

次の 3 つのタイプがあるとします。

class A { }
class B : A { }
class C : A { }

また、次の 3 つの方法があります。

DoSomething(A a){ }
DoSomething(B b){ }
DoSomething(C c){ }

List<A>タイプ B および C のオブジェクトを含む があります

私はこれをしたいと思います:

foreach(A a in list) { DoSomething(a) }

基になる型に最もよく一致するメソッドを呼び出すようにしますが、もちろんこれは常に呼び出しますDoSomething(A a)

正しいメソッド呼び出しを取得するために大量の型チェックを行いたくないので、クラス A、B、または C に何も追加したくありません。

出来ますか?

4

3 に答える 3

7

これは、静的に型付けされた言語での仮想ディスパッチに関するよく知られた問題です。1 つのパラメーター ( this) のみを「仮想的に」処理します。他のすべてのパラメーターの場合、メソッド呼び出しは引数の静的型を使用してバインドされます。リストは のリストであるAため、コードはオーバーロードを呼び出すだけAです。

宣言された目標を達成するには、複数のディスパッチが必要になります。言語は、に切り替えない限りそのままではこれを提供しないためdynamic、切り替えを行うか、自分で実装する必要があります。この決定を行うとき (および必要に応じて複数のディスパッチを実装する方法を決定するとき) には、考慮すべき多くのトレードオフがあるため、軽々しく実行しないでください。

于 2012-11-26T20:10:26.033 に答える
3

パフォーマンスにコストがかかりますが、これを実現する簡単な方法の 1 つは、動的ランタイム バインダーを使用することです。引数をdynamic次のようにキャストするだけです。

foreach(A a in list) { DoSomething((dynamic)a); }
于 2012-11-26T20:11:13.050 に答える
3

キーワードを使用する場合はdynamic、次のようなものだと思います

DoSomething((dynamic)a);

あなたのために仕事をします。

それ以外の場合、静的型では、次のように言うことができます

void DoSomething(A a)
{
  var aAsB = a as B;
  if (aAsB != null)
    DoSomething(aAsB);
  var aAsC = a as C;
  if (aAsC != null)
    DoSomething(aAsC);

  // general A case here
}

しかし、それはおそらくあなたが一連の型チェックと呼んでいるものです。

于 2012-11-26T20:11:36.890 に答える