243

What is the difference between <out T> and <T>? For example:

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

vs.

public interface IExample<T>
{
    ...
}
Cole Tobin
  • 8,881
  • 15
  • 47
  • 69
  • 1
    Good example would be IObservable and IObserver, defined in system ns in mscorlib. public interface IObservable, and public interface IObserver. Similarly, IEnumerator, IEnumerable – VivekDev Feb 06 '16 at 01:00
  • 3
    The best explanation I met: https://agirlamonggeeks.com/2019/05/29/vs-in-generic-interfaces-contravariance-vs-covariance-the-easier-part-1/ .(< in T> – Uladzimir Sharyi Aug 16 '19 at 08:55

5 Answers5

253

The out keyword in generics is used to denote that the type T in the interface is covariant. See Covariance and contravariance for details.

The classic example is IEnumerable<out T>. Since IEnumerable<out T> is covariant, you're allowed to do the following:

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

The second line above would fail if this wasn't covariant, even though logically it should work, since string derives from object. Before variance in generic interfaces was added to C# and VB.NET (in .NET 4 with VS 2010), this was a compile time error.

After .NET 4, IEnumerable<T> was marked covariant, and became IEnumerable<out T>. Since IEnumerable<out T> only uses the elements within it, and never adds/changes them, it's safe for it to treat an enumerable collection of strings as an enumerable collection of objects, which means it's covariant.

This wouldn't work with a type like IList<T>, since IList<T> has an Add method. Suppose this would be allowed:

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

You could then call:

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

This would, of course, fail - so IList<T> can't be marked covariant.

There is also, btw, an option for in - which is used by things like comparison interfaces. IComparer<in T>, for example, works the opposite way. You can use a concrete IComparer<Foo> directly as an IComparer<Bar> if Bar is a subclass of Foo, because the IComparer<in T> interface is contravariant.

janw
  • 7,168
  • 9
  • 31
  • 54
Reed Copsey
  • 539,124
  • 75
  • 1,126
  • 1,354
  • 5
    @ColeJohnson Because `Image` is an abstract class ;) You can do `new List() { Image.FromFile("test.jpg") };` with no problems, or you can do `new List() { new Bitmap("test.jpg") };` as well. The problem with yours is that `new Image()` isn't allowed (you can't do `var img = new Image();` either) – Reed Copsey Aug 20 '12 at 16:28
  • 4
    a generic `IList` is a bizarre example, if you want `object`s you don't need generics. – Jodrell Dec 18 '13 at 14:54
  • 7
    @ReedCopsey Aren't you contradicting your own answer in your comment? – MarioDS Sep 21 '15 at 10:05
78

For remembering easily the usage of in and out keyword (also covariance and contravariance), we can image inheritance as wrapping:

String : Object
Bar : Foo

in/out

shA.t
  • 15,880
  • 5
  • 49
  • 104
o0omycomputero0o
  • 2,984
  • 4
  • 29
  • 43
  • 15
    Isn't this the wrong way around? Contravariance = in = allows less derived types to be used in place of more derived. / Covariance = out = allows more derived types to be used in place of less derived. Personally, looking at your diagram, I read it as the opposite of the that. – Sam Shiles Aug 24 '17 at 07:19
  • co **u** variant (: for me – snr Mar 20 '20 at 11:25
61

consider,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

and the functions,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

The function that accepts ICovariantSkinned<Fruit> will be able to accept ICovariantSkinned<Fruit> or ICovariantSkinned<Banana> because ICovariantSkinned<T> is a covariant interface and Banana is a type of Fruit,

the function that accepts ISkinned<Fruit> will only be able to accept ISkinned<Fruit>.

Jodrell
  • 32,967
  • 4
  • 79
  • 120
51

"out T" means that type T is "covariant". That restricts T to appear only as a returned (outbound) value in methods of the generic class, interface or method. The implication is that you can cast the type/interface/method to an equivalent with a super-type of T.
E.g. ICovariant<out Dog> can be cast to ICovariant<Animal>.

shA.t
  • 15,880
  • 5
  • 49
  • 104
James World
  • 28,391
  • 9
  • 86
  • 116
  • 23
    I didn't realize that `out` enforces that `T` can be returned only, until I read this answer. The whole concept makes more sense now! – MarioDS Sep 21 '15 at 10:09
7

From the link you posted....

For generic type parameters, the out keyword specifies that the type parameter is covariant.

EDIT: Again, from the link you posted

For more information, see Covariance and Contravariance (C# and Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx

Brad Cunningham
  • 6,324
  • 1
  • 32
  • 39