<out T> vs Genericsの<T>


188

違いは何である<out T>とは<T>?例えば:

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

public interface IExample<T>
{
    ...
}

1
mscorlibのシステムnsで定義されているIObservable <T>とIObserver <T>が良い例です。パブリックインターフェイスIObservable <out T>、およびパブリックインターフェイスIObserver <in T>。同様に、IEnumerator <out T>、IEnumerable <out T>
VivekDev 2016

1
私が会った最高の説明:agirlamonggeeks.com/2019/05/29/…。(<in T> <–は、Tがパラメーターとしてメソッドにのみ渡せることを意味し、<out T> <–は、Tがメソッドの結果としてのみ返されます)
ウラジミールシャリィ

回答:


210

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>は共変とマークされ、になりました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>共変とマークすることはできません。

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


4
@ColeJohnson Imageは抽象クラスなので、;)new List<object>() { Image.FromFile("test.jpg") };問題なく実行することもnew List<object>() { new Bitmap("test.jpg") };、実行することもできます。あなたの問題new Image()は許可されていないことです(あなたもvar img = new Image();どちらもできません)
Reed Copsey

4
ジェネリックIList<object>は奇妙な例objectです。sが必要な場合、ジェネリックは必要ありません。
Jodrell

5
@ReedCopseyコメントであなた自身の答えに矛盾していませんか?
MarioDS 2015

64

簡単の使い方覚えるためinoutラッピングなどのキーワード(また、共変性と反変性)、我々はできる画像の継承を:

String : Object
Bar : Foo

イン/アウト


11
これは間違った方法ではありませんか?Contravariance = in =は、より多くの派生型の代わりに、より少ない派生型を使用できるようにします。/共分散= out =より少ない派生型の代わりに、より多くの派生型を使用できます。個人的には、あなたの図を見て、それとは反対のものとしてそれを読みました。
Sam Shiles

co uバリアント(:私の場合
snr

49

考えて、

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

そして機能、

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

受け入れる関数は受け入れるICovariantSkinned<Fruit>ことができるICovariantSkinned<Fruit>ICovariantSkinned<Bananna>、またはICovariantSkinned<T>共変インターフェイスでBananaあり、のタイプであるためFruit

受け入れる関数は受け入れるISkinned<Fruit>ことができるだけISkinned<Fruit>です。


37

out T」は、型Tが「共変」であることを意味します。これTは、ジェネリッククラス、インターフェイス、またはメソッドのメソッドで返される(送信)値としてのみ表示されるように制限します。つまり、タイプ/インターフェース/メソッドをスーパータイプの同等のものにキャストできるということですT
たとえば、ICovariant<out Dog>にキャストできますICovariant<Animal>


13
私がこの回答を読むまでは、それだけが返さoutれるT可能性があることを理解していませんでした。全体のコンセプトは今より意味があります!
MarioDS

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.