8

AddRange(IEnumerable) をリストに追加しようとすると、最近問題が発生しました。おそらく古典的な問題ですが、まだよくわかりません。

List パラメーターを期待するメソッドが List に満足していないことは理解しています。なぜなら、List に Base を追加しようとする可能性があるからです。これは明らかに不可能です。

しかし、これが正しく取得できれば、IEnumerables 自体は変更できないため、この場合は機能するはずです。

私が考えたコードは次のようになります。

class Foo
{
}

class Bar : Foo
{
}

class FooCol
{
    private List<Foo> m_Foos = new List<Foo> ();

    public void AddRange1(IEnumerable<Foo> foos)
    {
        m_Foos.AddRange (foos); // does work
    }

    public void AddRange2<T>(IEnumerable<T> foos) where T : Foo
    {
        m_Foos.AddRange (foos); // does not work
    }
}

class Program
{
    static void Main(string[] args)
    {
        FooCol fooCol = new FooCol ();

        List<Foo> foos = new List<Foo> ();
        List<Bar> bars = new List<Bar> ();

        fooCol.AddRange1 (foos); // does work
        fooCol.AddRange1 (bars); // does not work

        fooCol.AddRange2 (foos); // does work
        fooCol.AddRange2 (bars); // does work
    }
}

AddRange2 メソッドでヒントをコンパイラに渡そうとしましたが、これは単に問題に移動しました。

私の考え方は間違っていますか?これは言語の制限ですか、それとも仕様によるものですか?

IIRC、Java 1.5でこのような操作のサポートが追加されたので、将来的にC#にも追加されるのではないでしょうか...?

4

4 に答える 4

19

これは共分散であり、C# 4.0 / .NET 4.0 で修正される予定です。今のところ、一般的なオプションが最良の答えです (for -notIEnumerable<T> etc )IList<T>

しかし、ジェネリック メソッド内では、 の観点から考える必要がありますTCast<T>orOfType<T>を LINQ と共に使用して、同様のことを実現することもできます。

于 2009-03-11T12:17:04.103 に答える
2

C# 3.0 では、"Cast" 拡張メソッドを使用できます。System.Linq をインポートしてから、次のコードを使用する場合:

public void AddRange2<T>(IEnumerable<T> foos) where T : Foo
{
    m_Foos.AddRange (foos.Cast<Foo>());
}

その後、それはあなたのために働くはずです。

于 2009-03-18T17:22:53.553 に答える
0

拡張メソッドには回避策があります。

public static IEnumerable<TBase> ToBaseEnumerable<TBase, TDerived>( this IEnumerable<TDerived> items ) where TDerived : TBase {
    foreach( var item in items ) {
        yield return item;
    }
}
...
IEnumerable<Employee> employees = GetEmployees(); //Emplyoee derives from Person
DoSomethingWithPersons( employees.ToBaseEnumerable<Person, Employee>() );

しかし、「<Person, Employee>」は少しぎこちないです :/.

于 2009-03-11T12:24:15.413 に答える
0

もちろん、キャスト ソリューションはクラス キャスト例外を生成する可能性があります。数え切れないほどの拡張作業を投稿した人は、それは厄介だと言いました。私はそれを使用するかどうかわからない、厄介な半分だけの解決策を思いつきました:

public static class UpTo<T>
{
    public static IEnumerable<T> From<F>(IEnumerable<F> source) where F:T
    {
        // this cast is guaranteed to work
        return source.Select(f => (T) f);
    }
}

使用法:

IEnumerable哺乳類 = UpTo<哺乳類>.From(kennel.Dogs)

于 2009-09-25T22:23:09.627 に答える