5

私にはいくつかのクラスがあり、すべて同じ基本タイプから派生しています。

class basetype{}
class TypeA : basetype{}
class TypeB : basetype{}
...

それらの数はリストに保存されます。

List<basetype> myObjects

いつものように、これらのタイプはそれぞれ異なる方法で処理する必要があります。これで、それらを処理するための2つのメソッドと、パラメーターとしてベースタイプを受け取る1つのメソッドがあります。

HandleTypes(TypeA obj){}
HandleTypes(TypeB obj){}
HandleTypes(basetype obj)

現在、私のHandleAllTypesは次のようになっています。

string name = obj.GetType().Name
switch(name)
{
  case "TypeA":
    return HandleTypes(obj as TypeA);
  case "TypeB":
    return HandleTypes(obj as TypeB);
  ....
}

今これはがらくたです。のような方法はありますか

HandleTypes(obj ?"as derived type"?)

MSDNやその他のソースを検索しても、何も見つかりませんでした。

4

8 に答える 8

7

How about

HandleTypes( obj as dynamic );

?


サードパーティのクラスに対処しなければならなかったときに、これを数回使用しました。また、派生クラスが多数ある場合にも非常に役立ちます。

処理機能が実装されているかどうかを簡単に確認できます。

try {
   HandleTypes( obj as dynamic )
}
catch( RuntimeBinderException ex ) {
   // not implemented
}
于 2011-07-27T12:54:20.880 に答える
4
class basetype{
  public virtual void Handle(){
     // do only for base type 
  }
} 
class TypeA : basetype{
  public override void Handle(){
     // do only for Atype
  }
}
class TypeB : basetype{
  public override void Handle(){
     // do only for Btype
  }
}

foreach(baseType obj in myObjects)
    obj.Handle() 
于 2011-07-27T12:58:00.393 に答える
1

ここで必要なのは仮想メソッドだと思います。

基本的に、基本クラスで仮想メソッドを宣言します。これは、DoWork()と呼ばれます。

これで、TypeAでこの仮想メソッドをオーバーライドできます。TypeBでもオーバーライドできます。

ベースオブジェクトでDoWork()を呼び出すと、そのメソッドが使用されます。typeAのオブジェクトでDoWork()を呼び出すと、そのメソッドが使用されます。

基本的に、正しいクラスでオーバーライドする限り、正しいメソッドが使用されます。

詳細: http: //msdn.microsoft.com/en-us/library/aa645767 (v = vs.71).aspx

于 2011-07-27T12:57:57.503 に答える
1

必要なのは、C#では直接利用できないダブルディスパッチです。ビジターパターンに基づくソリューションは、ビジターを呼び出すbasetype抽象メソッドを宣言することにより、ダブルディスパッチを模倣するために使用できますAccept。この場合、オーバーロードの結果によって正しいメソッドが選択されます。

abstract class basetype
{
  //..
  public abstract void Accept(Visitor v);
  //..
}

class TypeA
{
  //..
  //..
  public override void Accept(Visitor v) { v.Visit(this); }
}

abstract class Visitor
{
  public abstract void Visit(TypeA a);
  public abstract void Visit(TypeB b);
}

から派生したクラスに「Handling」メソッドを配置すると、Visitor通常のオーバーロード解決で問題を解決できます。私の意見では、これは反射を使用するよりもすっきりとしたデザインです。

于 2011-07-27T12:58:42.287 に答える
1

これが、あなたがやろうとしていることを理解するための別の方法です。

方法:

void HandleTypes(IEnumerable<Apple> apples)
void HandleTypes(IEnumerable<Banana> banana)
void HandleTypes(IEnumerable<Orange> oranges)
void HandleTypes(IEnumerable<Fruit> fruit)

呼び出し元:

List<Fruit> fruitbasket = GetBasket();

HandleTypes(fruitbasket.OfType<Apple>());
HandleTypes(fruitbasket.OfType<Orange>());
HandleTypes(fruitbasket.OfType<Banana>());
HandleTypes(fruitbasket.OfType<Fruit>());

またはによって呼び出されます:

List<Fruit> fruitbasket = GetBasket();
ILookup<Type, Fruit> fruitLookup = fruitBasket.ToLookup(x => x.GetType());

foreach(IGrouping<Type, Fruit> fruitRollup in fruitLookup)
{
  switch(fruitRollup.Key.Name)
  {
    case "Apple" :
      return HandleTypes(fruitRollup.OfType<Apple>());
      break;
    case "Banana" :
      return HandleTypes(fruitRollup.OfType<Banana>());
      break;
    case "Orange" :
      return HandleTypes(fruitRollup.OfType<Orange>());
      break;
    case "Fruit" :
      return HandleTypes(fruitRollup.OfType<Fruit>());
      break;
    default :
      return HandleTypes(fruitRollup.OfType<Fruit>());
      break;
  }
}
于 2011-07-27T12:59:18.690 に答える
1

どのメソッドにバインドするかがわからないため、コンパイル時にそのような正しいメソッドを選択することはできません。リフレクションを使用することもできます。

タイプを分割するために、私は次のようなことをする傾向があります:

TypeA aRef = obj as TypeA;

if (aRef != null)
    HandleTypes(aRef);

ただし、理想的な方法は、継承を使用HandleTypeして基本クラスにメソッドを配置し、必要に応じて派生型に作成することvirtualですoverride。ただし、何らかの理由でこれを選択できない場合があります。

于 2011-07-27T12:48:58.900 に答える
1

通常、「HandleTypes」機能を basetype/TypeA/TypeB に実装し、 を呼び出すだけでobj.HandleTypes()、ポリモーフィズムにそれを処理させることができます。それができない理由はありますか?

于 2011-07-27T12:49:55.347 に答える
0

あなたが求めていることは不可能です。メソッド呼び出しはコンパイル時に解決され、その後は変更されませんが、実行時の値に基づいて特定のメソッドを選択するように求められます。これはデリゲートを使用した場合にのみ可能ですが、デリゲートを使用した場合でも、デリゲート宣言で指定されたタイプよりも派生したタイプに引数をアップキャストすることはできません。

于 2011-07-27T12:58:11.193 に答える