Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning IEnumerable (Covariance)

Since IEnumerable has a covariant parameter in C# 4.0 I am confused how it is behaving in the following code.

public class Test
{
    IEnumerable<IFoo> foos;

    public void DoTestOne<H>(IEnumerable<H> bars) where H : IFoo
    {
        foos = bars;
    }

    public void DoTestTwo(IEnumerable<IBar> bars)
    {
        foos = bars;
    }
}
public interface IFoo
{
}
public interface IBar : IFoo
{
}

So basically the DoTestOne method doesn't compile while DoTestTwo does. In addition to why it doesn't work, if anyone knows how I can achieve the effect of DoTestOne (assigning an IEnumberable<H> where H : IFoo to an IEnumberable<IFoo>) I would appreciate the help.

like image 749
tleef Avatar asked Oct 18 '12 19:10

tleef


2 Answers

If you know that H will be a class, this does work:

    public void DoTestOne<H>(IEnumerable<H> bars) where H : class, IFoo
    {
        foos = bars;
    }

The issue here is that if H is a value type, the covariance is not exactly what you'd expect, as IEnumerable<MyStruct> actually returns the value types whereas IEnumerable<IFoo> has to return boxed instances. You can use an explicit Cast<IFoo> to get around this, if necessary.

like image 187
Dan Bryant Avatar answered Sep 21 '22 10:09

Dan Bryant


You simply need a cast to IEnumerable<IFoo> in there:

public void DoTestOne<H>(IEnumerable<H> bars) where H : IFoo
{
    foos = (IEnumerable<IFoo>)bars;
}

Edit courtesy of Dan Bryant: using foos = bars.Cast<IFoo>() instead of above circumvents the InvalidCastException when H is a struct.

like image 30
McGarnagle Avatar answered Sep 22 '22 10:09

McGarnagle