web-dev-qa-db-ja.com

IEnumerable(of T)が拡張メソッドレシーバーとして受け入れられないのはなぜですか

コードの前にquestionを記入してください:

_IEnumerable<T>_を期待する拡張メソッドのレシーバーとして_where T : ITest_ _this IEnumerable<ITest>_が受け入れられないのはなぜですか?

そしてcode

私は3つのタイプがあります:

_public interface ITest { }
public class Element : ITest { }
public class ElementInfo : ITest { }
_

そして2つの拡張メソッド:

_public static class Extensions
{
    public static IEnumerable<ElementInfo> Method<T>(
        this IEnumerable<T> collection) 
        where T : ITest
    {
→        return collection.ToInfoObjects();
    }

    public static IEnumerable<ElementInfo> ToInfoObjects(
        this IEnumerable<ITest> collection)
    {
        return collection.Select(item => new ElementInfo());
    }
}
_

(マークされた行で)発生するコンパイラエラー:

_CS1929_:_'IEnumerable<T>'_には_'ToInfoObjects'_の定義が含まれておらず、最適な拡張メソッドオーバーロード'Extensions.ToInfoObjects(IEnumerable<ITest>)'にはタイプ_'IEnumerable<ITest>'_のレシーバーが必要です

これはなぜですか? ToInfoObjects拡張メソッドのレシーバーは_IEnumerable<T>_であり、ジェネリック型制約により、TITestを実装する必要があります。

なぜレシーバーは受け入れられないのですか?私の推測では、_IEnumerable<T>_の共分散ですが、よくわかりません。

ToInfoObjectsを変更して_IEnumerable<T> where T : ITest_を受け取るようにすると、すべて問題ありません。

16
Kornelije Petak

このことを考慮:

public struct ValueElement : ITest { }

この:

IEnumerable<ValueElement> collection = ...
collection.Method(); //OK, ValueElement implement ITest, as required.
collection.ToInfoObjects() //Error, IEnumerable<ValueElement> is not IEnumerable<ITest>
                           //variance does not work with value types.

そのため、Methodに許可されているすべての型がToInfoObjectsにも許可されているわけではありません。 class制約をTMethodに追加すると、コードがコンパイルされます。

14
user4003407