10

オブジェクトのリストをダウンキャストして、リスト内の各オブジェクトを派生クラスのオブジェクトにダウンキャストするにはどうすればよいですか?

これがシナリオです。

の基本アイテムを持つ基本クラスと、Listそれを継承する2つのクラスがあります。

public class BaseClass
{
    public List<BaseItem> items;
    protected BaseClass()
    {
        // some code to build list of items
    }
}
public class DerivedClass : BaseClass
{
    public DerivedClass : base() {}
}
public class AnotherDerivedClass : BaseClass
{
    public AnotherDerivedClass : base() {}
}

public class BaseItem {}
public class DerivedItem : BaseItem {}
public class AnotherDerivedItem : BaseItem {}

アイデアは、アイテムのリストを作成するために必要なコードを複製する必要がないことです。には必要な基本的なものがすべて揃っており、派生アイテムの1つにBaseItemいつでもダウンキャストできます。BaseItem

それらのリストがあると問題が発生します。のListは、すべての派生クラスに含まれている必要がBaseItemあるため、で宣言されています。BaseClassしかし、実行時にアクセスすると、派生クラスにダウンキャストできないようです。

4

4 に答える 4

11

LINQの使用:

    var baseList = new List<BaseClass>();
    var derivedList = baseList.Cast<DerivedClass>();

注:通常、ダウンキャストする必要があるのは「匂い」であり、継承階層が間違っているか、正しく実装されていないことを示します。基本クラスを持つという考え方は、個々のサブクラスタイプにダウンキャストすることなく、すべてのサブクラスをスーパークラスとして扱うことができるということです。

代わりに、スーパークラスのコレクションから特定の派生クラスを「フィッシュアウト」するCastために使用することもできます。OfTypeしかし、繰り返しになりますが、それを行う必要はありません。

なぜサブクラスが必要なのか、自問してみてください。おそらく、いくつかの機能を基本クラスに移動する必要がありますか?

于 2011-03-08T15:01:05.867 に答える
6

あなたがやりたいのはジェネリックを使うことだと思います:

public class BaseClass<T> where T: BaseItem, new()
{
    public List<T> items;
    protected BaseClass()
    {
        items = new List<T>();
        T item = new T();
        item.SomePropertyOfBaseItem=something;
        items.Add(item);
    }
}

public class DerivedClass: BaseClass<DerivedItem>

これにより、itemsinDerivedClassがになりますList<DerivedItem>whereから派生したタイプのみを使用できるように強制しますBaseItem

編集:「ダウンキャスト」、つまり型を派生型にキャストすることは、実際にはここでやろうとしていることではありません。派生リストオブジェクトは、設計により特定の派生アイテムタイプを使用することを目的としており、おそらく、派生リストクラスに派生タイプのインスタンス化されたオブジェクトを格納する必要があります。

したがって、これはジェネリックスを使用しなくても問題なく機能する可能性があります。List<BaseItem>は、から派生したアイテムを完全に格納できますBaseItem。ただし、派生プロパティにアクセスするには、キャストを使用してリストからこれらのオブジェクトを参照する必要があります(他の回答で説明されています)。しかし、それは単にオブジェクトをそのTrueTypeに「キャスト」することです。Genericsは、これらのオブジェクトへの強い型付きアクセスを直接提供する方法を提供します。

基本的に、オブジェクトのスーパークラスであるコンテナにオブジェクトを格納しても、オブジェクトについては何も変更されません。オブジェクトが派生元のより単純な型であるように見せることで、コードがオブジェクトを参照する方法が変更されるだけです。

于 2011-03-08T14:59:28.210 に答える
0
public class Zoo
{
     public List<Animal> items;
     protected BaseClass()
     {         // some code to build list of items     }
 }

public class PettingZoo : Zoo
{
     public PettingZoo : base() {}
}

public class CatComplex : Zoo
{
     public CatComplex : base() {}
}

public class Animal {}
public class Sheep : Animal {}
public class Tiger : Animal {}

..。

PettingZoo myZoo = new PettingZoo();
myZoo.items.Add(new Tiger());

PettingZooは動物の種類を制限する必要があるため、PettingZooはZooと互換性がありません。そのため、この設計はリスコフの置換原則に失敗します。

于 2011-03-08T15:15:42.510 に答える
0

次のように、LINQを使用して基本クラスの要素を反復処理し、各要素をダウンキャストすることもできます。

var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.ForEach(v => derivedList.Add((DerivedClass)v));

キャストする前に各要素の派生タイプを確認する必要がある場合:

var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.OfType<DerivedClass>().ToList().ForEach(v => derivedList.Add(v));

詳細については、次の記事を参照してください。

于 2015-09-23T02:48:32.440 に答える