1

IList から継承するインターフェイスがあります。

public interface IBase {}
public class Derived : IBase {}
public interface IMyList : IList<IBase> {}

IMyListtype の変数をtypeIList<Derived>またはにキャストしたいのですがList<Derived>、どちらか簡単または最も理にかなっています。これを行う最善の方法は何ですか?

私は.NET 3.5を使用していることに注意してください

4

6 に答える 6

10

発生する可能性のある問題が多数あるため、直接キャストは適切ではありません (IMyList以外の型が含まれている可能性がDerivedあるなど)。

リストを変更していない限り (その場合IEnumerable<Derived>は機能します)、次のように簡単にできます。

var validItems = myList.Cast<Derived>();

そして、結果を反復処理します。

編集

以下の OP のコメントに基づいて、言及すべきことが他に 2 つあります。

1) が必要な場合はIList<Derived>、単純に上記に追加して呼び出すことができますmyList.Cast<Derived>().ToList();

2) それらが本当に要件である場合、コードは意味がありません。オブジェクトIMyListのみを含む必要がある場合は、から派生する必要があります。インターフェイスを実装する型が 1 つしかないことはわかっていますが、コンパイラはそれほど具体的ではないことに注意してください。DerivedIMyListIList<Derived>IBase

インターフェイスを使用するためだけにどこでもインターフェイスを使用しても、誰の役にも立ちません!

于 2011-07-07T14:36:58.497 に答える
4

キャストされた結果を、 を受け取る関数に渡していますIList<Derived>

その時、あなたは自分で考案した痛みの世界にいます。私のアドバイスは、循環依存の問題を解決する他の方法を最初に見つけることです。あなたが発見したように、可能な実装が1つしかないインターフェイスにすべてを作成することは、その問題を解決するための苦痛な方法です。お勧めしません。

それができない場合は、問題のある関数を修正して、IList<IBase>、 、IEnumerable<IBase>または のいずれかを取るようにしますIEnumerable<Derived>。できれば IEnumerable ソリューションの 1 つです。実際、リストを取るほとんどのメソッドは、シーケンスのみを必要とします。ここでリストが必要な理由を説明できれば、回避策を見つけるのに役立ちます。

IList<IBase>orを取ることができればIEnumerable<IBase>完了です。目的の型に暗黙的に変換できるものが既に手元にあります。

を取得できる場合は、IEnumerable<Derived>(myListOfIBase.Cast<Derived>()それらのすべてが Derived であることが本当にわかっているmyListOfIBase.OfType<Derived>()場合) または (それらの一部が Derived 型ではない可能性があり、それらをスキップしたい場合) と言ってIEnumerable<Derived>、効率的に使用する を取得できます。基礎となるリスト。

問題のある関数を変更できない場合は、基になるリストを効率的に使用する独自のクラスを作成できます。

sealed class MyProxyList : IList<Derived>
{
    IList<IBase> underlyingList;
    public MyProxyList(IList<IBase> underlyingList)
    {
        this.underlyingList = underlyingList;
    }
    ... now implement every member of IList<Derived> as 
    ... a call to underlyingList with a cast where necessary 
}

そしてMyProxyList、メソッドに new を渡します。

于 2011-07-07T15:21:32.070 に答える
1

.Net 3.5 には一般的な共分散がありません。デモンストレーションするには:

[TestFixture]
class Class1
{
    [Test]
    public void test()
    {
        var list = new List<SuperClass>();
        list.Add(new SuperClass());

        var castedList = ((List<BaseClass>)list);
    }
}

public class BaseClass
{
    public string a { get; set; }
}

public class SuperClass : BaseClass
{
    public string b { get; set; }
}

正常にコンパイルされません。

Justin Niessner の応答では、回避策は

var validItems = myList.Cast<Derived>();  

掲載されました。これは機能しますが、リスト全体の列挙になり (この列挙は延期されます)、列挙型も返します。リストを変換して最終的に IList にするには、次を使用できます

[Test]
public void CanConvertListToBaseClass()
{
    var list = new List<SuperClass>();
    list.Add(new SuperClass());

    var castedList = list.Cast<BaseClass>().ToList();
    Assert.That(castedList, Is.InstanceOf<IList<BaseClass>>());
}

ただし、これはかなり強引なアプローチです。これにより、新しい個別の IList が作成され、リスト全体の列挙が強制されます。

于 2011-07-07T14:38:00.907 に答える
0

今後、すべてのインスタンスのタイプが であると確信できる場合は、前述のパフォーマンスの問題で をDerived使用できます。Cast<>()それ以外のものDerivedがリストに含まれる可能性がある場合は、代わりに使用することをお勧めしますOfType<Derived>()。非Derivedアイテムは投げる代わりに除外されます。

于 2011-07-07T15:35:02.493 に答える
0

IList<T>タイプ の読み取り操作書き込み操作が許可されているためT、インターフェイスは共変でも反変でもありません。したがって、あなたが望むことはできません。次のコードを想像してください。

var myList = new MyListImlementation();
myList.Add(new BaseImplementation());
var castList = (IList<Derived>)myList; // this is what you want

// this would break, because myList contains elements of type BaseImplementation.
Derived d = castList[0];               
于 2011-07-07T14:37:09.990 に答える
-2

これは .Net 3.5 ではできませんが、.Net 4.0 ではできます。

于 2011-07-07T14:36:47.087 に答える