1. ホーム
  2. c#

[解決済み】ジェネリックの<out T>と<T>の比較

2022-04-17 20:20:52

質問

とはどのような違いがあるのでしょうか? <out T><T> ? 例えば

public interface IExample<out T>
{
    ...
}

vs.

public interface IExample<T>
{
    ...
}

解決方法は?

その out キーワードは、インターフェイスの型Tが共変であることを示すために使用されます。 参照 共分散と共分散 をご覧ください。

古典的な例としては IEnumerable<out T> . このため IEnumerable<out T> は共変数なので、次のようにしてもよい。

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

文字列はオブジェクトから派生するので、論理的にはうまくいくはずですが、これが共変数でなければ、上の2行目は失敗します。 以前は ジェネリックインターフェースにおける分散 がC#とVB.NETに追加されたとき(VS 2010の.NET 4)、これはコンパイル時のエラーになりました。

.NET 4 以降は。 IEnumerable<T> はcovariantとマークされ、次のようになりました。 IEnumerable<out T> . このため IEnumerable<out T> はその中の要素だけを使用し、要素を追加したり変更したりすることはありません。 文字列の列挙可能なコレクションをオブジェクトの列挙可能なコレクションとして扱うのは安全です。 コバリアント .

のような型ではうまくいきません。 IList<T> というのは IList<T> には Add メソッドを使用します。 仮にこれが許されるとすると

IList<string> strings = new List<string>();
IList<object> objects = strings;  // NOTE: Fails at compile time

そして、呼び出すことができます。

objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object

もちろん、これは失敗です。 IList<T> は共変量とマークすることはできません。

また、オプションとして in - これは、比較インターフェースなどで使用されます。 IComparer<in T> は、例えば、逆の動作をします。 具体的な IComparer<Foo> を直接 IComparer<Bar> もし Bar のサブクラスです。 Foo というのは IComparer<in T> インターフェースは 反変数 .