5

わかりました、基本クラスから派生したいくつかの異なるオブジェクトがあり、それらの束をリストに入れました。リストをループして、それぞれをメソッドにプッシュしたい。それぞれの型シグネチャを持つ個別のメソッドがありますが、コンパイラは不平を言っています。誰かが理由を説明できますか?これは Generics を使用する機会ですか? もしそうなら、どのように?

class Base { }
class Level1 : Base { }
class Level2 : Level1 { }

...

List<Base> oList = new List<Base>();
oList.Add(new Level1());
oList.Add(new Level2());

...

...
foreach(Base o in oList)
{
   DoMethod(o);
}

...

void DoMethod(Level1 item) { }
void DoMethod(Level2 item) { }

私は何を間違っていますか?

4

8 に答える 8

8

オーバーロードはコンパイル時に解決され、DoMethod(Base item)メソッドがないため、呼び出しを解決できません。リストとループから抜け出すと、効果的に次のように記述できます。

Base o = GetBaseFromSomewhere();
DoMethod(o);

コンパイラはDoMethod、 type の単一の引数に適用できる呼び出されたメソッドを見つける必要がありBaseます。そのような方法はないため、失敗します。

ここにはいくつかのオプションがあります。

  • Markos が言うように、C# 4 で動的型付けを使用して、参照するオブジェクトの実際の型を使用して、実行時に C# コンパイラにオーバーロードを適用させることができます。o
  • ビジター パターンを使用して効果的にダブル ディスパッチを取得できます (私はこれがあまり好きではありません)。
  • asまたはを使用できますis

    Level1 x = o as Level2;
    if (x != null)
    {
        DoMethod(x); // Resolves to DoMethod(Level1)
    } 
    else
    {
        Level2 y = o as Level2;
        if (y != null)
        {
            DoMethod(y); // Resolves to DoMethod(Level2)
        }
    }
    

    繰り返しますが、これはかなり醜いです

  • 可能であれば、通常の継承を使用できるように、現在行っていることを再設計します
于 2010-08-05T20:36:32.243 に答える
3

メソッドのオーバーロードでは、実行時の型ではなく、変数の静的型が使用されます。

継承とオーバーライドを使用したい。

class Base { public virtual void DoMethod() { /* ... */  } }
class Level1 : Base { public override void DoMethod() { /* ... */ } }
class Level2 : Level1 { public override void DoMethod() { /* ... */ } }
于 2010-08-05T20:37:17.527 に答える
2

どのメソッドが呼び出されるかは、実行時ではなくコンパイル時に決定されるため、コンパイラはどのメソッドを呼び出すかを知ることができません。2 つのオプションがあります。オブジェクトのタイプを切り替えて適切なメソッドを呼び出すか、.NET 4 を使用している場合は、動的タイプを使用します。

foreach(dynamic o in oList)
{
   DoMethod(o);
}
于 2010-08-05T20:37:37.123 に答える
2

DoMethod(Base item) メソッドがありません。オーバーロードはポリモーフィックではありません。これは通常、仮想メソッドを使用して行われます。

class Base {
    public virtual void DoMethod() {...}
}
class Level1 : Base {
    public override void DoMethod() {...}
}
// etc..

foreach(Base o in oList)
{
    o.DoMethod();
}
于 2010-08-05T20:38:53.343 に答える
1

foreach ループでoは、タイプがBaseあり、どちらのDoMethodオーバーロードもBaseインスタンスを取りません。可能であれば、2 つのサブクラスに移動DoMethodしてオーバーライドする必要があります。Base

public class Base
{
    public virtual void DoMethod() { ... }
}
于 2010-08-05T20:39:40.193 に答える
1

マークの答えを拡張するには、 DoMethod は、リスト内の各項目で呼び出す Base の仮想メソッドである必要があります。

于 2010-08-05T20:39:43.250 に答える
0

詳細はわかりませんが、継承するのが本当に適切でない状況では、代わりにインターフェースを使用できます。

インターフェイスを宣言し、各クラスに実装すると、インターフェイスに直接キャストして、そこから関数を実行できるようになります。私のC#は少し不安定ですが、

Interface IMethodizable
{
   void DoMethod();
}

class Level1 : IMethodizable {
  void DoMethod(){
    //insert code here
  }
}

class Level2 : IMethodizable {
  void DoMethod(){
    //insert code here
  }
}

これは、クラスに共通するのがそのメソッドだけである場合に特にうまく機能します。これは、基本クラスに仮想化されたメソッドを設定してオーバーライドするのと非常によく似ています。したがって、このパターンは、継承すべきでない場合にのみ優れています。そうでない場合、DoMethodは、baseなどから継承していない他のオブジェクトでも実行する必要があります。

于 2010-08-05T21:22:21.717 に答える