Search code examples
c#genericscovariance

<out T> vs <T> in Generics


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

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

vs.

public interface IExample<T>
{
    ...
}

Solution

  • 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(7); // 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.