tags:

views:

110

answers:

2

Can anyone tell me why this does not work? I would have thought the constraint would make it valid.

public class ClassA<T> where T : ICommon
{
    public ClassA()
    {
        ClassB b = new ClassB();
        IEnumerable<T> alist = new List<T>;
        b.Items = alist; 
        //Error: cannot convert from IEnumerable<T> to IEnumerable<ICommon>'
    }

}


public class ClassB
{
    public IEnumerable<ICommon> Items { get; set;}
    ....
}
+12  A: 

This will work in C# 4 with a tweak, but not in C# 3. What you're looking for is generic variance, which has been supported in the CLR since .NET 2.0, but not in C# until v4.

Even in C# 4, you need to also constrain T to be a reference type - as covariance doesn't work over value types. For example, List<int> can't be converted to IEnumerable<IComparable> even though int implements IComparable.

Having tweaked your code a bit (there were a few typos, effectively), this compiles with the C# 4 compiler:

using System.Collections.Generic;

public interface ICommon {}

// Note the "class" part of the constraint
public class ClassA<T> where T : class, ICommon
{
    public ClassA()
    {
        ClassB b = new ClassB();
        IEnumerable<T> alist = new List<T>();
        b.Items = alist; 
    }   
}

public class ClassB
{
    public IEnumerable<ICommon> Items { get; set;}
}

If you're stuck in C# 3 and .NET 3.5, an alternative would be to use Cast<T>():

b.Items = alist.Cast<ICommon>(); 
Jon Skeet
Interesting, thanks! (And my scrappy code now tidied up, sir ;) - embarrassingly sloppy without intellisense!)
UpTheCreek
+3  A: 

This is called covariance (or contra? I'm not sure), and is working only in C# 4.0.
You cannot cast IEnumerable<Common> to IEnumerable<ICommon>. (when Common implements ICommon.)

Try using

b.items = from f in alist select (T)f; 
Yossarian