SOReader
SOReader

Reputation: 6017

IEnumerable<T> conversion

Given the following:


class Base<T> {/*...*/}
class Der<T>: Base<T> {/*...*/}

interface Sth<T>{
  IEnumerable<Base<T>> Foo {get;}
}

// and implementation...
class Impl<T>: Sth<T> {
  public IEnumerable<Base<T>> Foo {
    get {
      return new List<Der<T>>();
    }
  }
}

How can I get this to compile? The error is, obviously, not implicit conversion found from List<Der<T>> to List<Base<T>>. If I cast it explicitly InvalidCastException occurs.

Upvotes: 5

Views: 2796

Answers (5)

qxn
qxn

Reputation: 17584

These answers helped me out, and I just wanted to post my solution for a similar problem I had.

I wrote an extension method for IEnumerable that automatically casts TSource whenever I want to convert a List<Foo> to an IEnumerable<Bar> (I'm still on 3.5).

public static SpecStatus Evaluate<TSource, TSpecSource>(this IEnumerable<TSource> source, ISpec<IEnumerable<TSpecSource>> spec)
        where TSource : TSpecSource
{
    return spec.Evaluate(source.Cast<TSpecSource>());
}

Upvotes: 0

bcat
bcat

Reputation: 8941

The conversion you're trying to make isn't supported as of version 3.5 of the .NET Framework. It will be supported in version 4.0 (Visual Studio 2010) due to the addition of generic covariance/contravariance. While this will still not allow you to cast List<Der> to List<Base>, it will allow you to cast IEnumerator<Der> (which the list implements) to IEnumerator<Base>.

In the meantime, you can write your own class that implements IEnumerable<Base> and returns a custom IEnumerator<Base> that simply wraps List<Der>'s IEnumerator<Der>. Alternatively, if you are using the .NET Framework version 3.5, you can use the Cast extension method, as others have suggested.

Upvotes: 6

FacticiusVir
FacticiusVir

Reputation: 2077

You can use LINQ to cast from List<Der<T>> to an IEnumerable<Base<T>>, by using:

class Impl<T>: Sth<T>
{
    public IEnumerable<Base<T>> Foo
    {
        get
        {
            return new List<Der<T>>().Cast<Base<T>>();
        }
    }
}

As the other answers have stated, generic convariance is not supported in v3.5, but you can use LINQ to created a wrapper object that implements IEnumerable<Base<T>>.

Upvotes: 1

itowlson
itowlson

Reputation: 74802

List<Der<T>> is not convertible to List<Base<T>> because the latter can have a Base<T> added to it and the former can't.

You can resolve this using the Cast extension method: return new List<Der<T>>().Cast<Base<T>>();

Upvotes: 4

CRice
CRice

Reputation: 12567

To make it compile...

class Impl<T> : Sth<T>
{
    public IEnumerable<Base<T>> Foo
    {
        get
        {
            return new List<Base<T>>(); //change the List type to Base here
        }
    }
} 

You could always do something like this too, which would return the IEnumerable of the Base class from an implementation of Der

class Impl<T> : Sth<T>
{
    public IEnumerable<Base<T>> Foo
    {
        get
        {
            List<Der<T>> x = new List<Der<T>>();

            foreach (Der<T> dt in x)
            {
                yield return dt;
            }
        }
    }
} 

Upvotes: 1

Related Questions