Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why IEnumerable<T> is defined as IEnumerable<out T>, not IEnumerable<T> [duplicate]

Tags:

c#

linq

c#-4.0

Possible Duplicate:
Why was IEnumerable<T> made covariant in C# 4?

I was taking a look on MSDN for IEnumerable<T> interface definition, and see:

public interface IEnumerable<out T> : IEnumerable

I was wondering why T is defined as out, why not?

public interface IEnumerable<T> : IEnumerable

What is the reason for this?

like image 933
cuongle Avatar asked Sep 14 '12 12:09

cuongle


People also ask

What is IEnumerable T?

IEnumerable<T> is the base interface for collections in the System. Collections. Generic namespace such as List<T>, Dictionary<TKey,TValue>, and Stack<T> and other generic collections such as ObservableCollection<T> and ConcurrentStack<T>.

What does IEnumerable mean in C#?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.

Why do we need IEnumerable in C#?

IEnumerable in C# is an interface that defines one method, GetEnumerator which returns an IEnumerator interface. This allows readonly access to a collection then a collection that implements IEnumerable can be used with a for-each statement.

Is IEnumerable covariance?

When calling PrintAnimals , the compiler uses covariance to convert IEnumerable<Cat> to IEnumerable<Animal> . This is correct, because the IEnumerable interface is marked as covariant using the out annotation.


2 Answers

More information can be found here.

The out makes the type parameter covariant. That is, you can use either the type or any derived types. Note that out only works this way with generics, it has a different meaning when used in method signatures (though you probably already knew that).

Here is the example taken from the referenced page:

// Covariant interface. 
interface ICovariant<out R> { }

// Extending covariant interface. 
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface. 
class Sample<R> : ICovariant<R> { }

class Program
{
    static void Test()
    {
        ICovariant<Object> iobj = new Sample<Object>();
        ICovariant<String> istr = new Sample<String>();

        // You can assign istr to iobj because 
        // the ICovariant interface is covariant.
        iobj = istr;
    }
}

As you can see, the out in the interface signature allows you to assign an ICovariant<String> to an ICovariant<Object> variable, as String derives from Object. Without the out keyword, you would be unable to do this, as the types would be different.

You can read more about covariance (and the related contravariance) here.

As other answers have pointed out, IEnumerable was only made covariant in .NET 4. Trying to write code such as:

IEnumerable<Object> strings = new List<string>();

will compile in .NET 4 and later versions, but not in previous versions.

like image 64
Daniel Avatar answered Sep 30 '22 19:09

Daniel


The out type parameter specifier denotes covariance.

In practice,

If I define two interfaces.

interface ISomeInterface<T>
{
}

interface ISomeCovariantInterface<out T> 
{
}

Then, I implement them like this.

class SomeClass<T> : ISomeInterface<T>, ISomeCovariantInterface<T>
{
}

Then I try to compile this code,

ISomeCovariantInterface<object> covariant = new SomeClass<string>(); // works
ISomeInterface<object> invariant = new SomeClass<string>(); // fails

// Cannot implicitly convert type 'SomeClass<string>' to 'ISomeInterface<object>'.
// An explicit conversion exists (are you missing a cast?)

The is because the covariant interface allows more derived instances, where as, the standard interface does not.

Fiddle Here

like image 40
Jodrell Avatar answered Sep 30 '22 17:09

Jodrell