destator
destator

Reputation: 171

C# generic constraints for IEnumerable

public interface I {
}
public class A : I {
}

The compiler takes explicit IEnumerable<A> as IEnumerable<I> :

public void Test() {
    IEnumerable<A> a = new List<A>();
    new List<I>().AddRange(a);
}

But with generic constraints, we get:

public void Test<T>() where T : I {
    IEnumerable<T> t = new List<T>();
    new List<I>().AddRange(t);
}
                          ^^^
Argument 1: cannot convert from 'IEnumerable<T>' to 'IEnumerable<I>'

However, this compiles fine.

public void Test<T>(T t) where T : I {
    new List<I>().Add(t);
}

Hence the question: is this a correct behavior, or is it a bug?

Upvotes: 8

Views: 2100

Answers (2)

samjudson
samjudson

Reputation: 56893

This has to do with Covariance and Contravariance. Suffice to say it is not a bug, but a feature.

For an indepth look at this I recommend Eric Lippert's blog post series here:

http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1502935

The problem is that generic covariance only applies for reference types. For example, a List<int> is not* an IEnumerable<Comparable>, but a List<string> is.

So if you constrain T to be a reference type, it compiles:

public void Foo<T, I>() where T : class, I 
{
    IEnumerable<T> t = new List<T>();
    new List<I>().AddRange(t);
}

Upvotes: 14

Related Questions