Question

Let's say I have two classes,

class A
{
}

class B : A
{
}

I have a method which accepts a parameter foo of type IEnumerable<A>;

void AMethod(IEnumerable<A> foo)
{
}

but instead pass in a value of type IEnumerable<B>.

AMethod(new[] { new B() });

This compiles and executes, though at execution foo has been implicitly cast to IEnumerable<B>. Now let's say my IEnumerable<B> contains objects of type A (I don't believe it matters whether they're mixed or all the same). When I call foo.Any() I get an exception:

Unable to cast object of type 'A' to type 'B'

I understand that I can't convert a base class to a subclass, but that's not what I'm trying to do (in fact at this point in execution, I don't even care what type it is). I guess LINQ is inherently trying to make this conversion, probably based on the fact that foo is type IEnumerable<B>. So, it seems as though I need to write two separate methods, one which handles IEnumerable<A> and one which handles IEnumerable<B>. I don't understand why I would need to do this. Any thoughts?

EDIT:

There's some dynamic casting and transformation going on that manages to spit out a IEnumerable<B> populated with 'A's, which until now I thought was impossible too. I'll do my best to translate what's happening leading up to this method call:

protected void SetDynamicData(dynamic data)
{
  _data = data;
  IsB = typeof(IBInterface).IsAssignableFrom(_data.DataType);
}

...

var foo = IsB ? _data.Cast<B>() : data.Cast<A>();
return BuildJqGridData<A, B, int>(gridModel, foo);
Was it helpful?

Solution

An IEnumerable<B> cannot contain objects of type A because and A is not a B.

I can write this code,

IEnumerable<B> dodgy = (new[] { new A() }).Cast<B>();

It will compile, despite being obviously wrong. The compiler assumes I know what I'm doing. Remember that no item in the IEnumerable sequence has yet been evaluated.

When I write code that evaluates a member of dodgy I get exception because an A is not a B and does not support casting to B.

I can write

IEnumerable<A> fine = new[] { new B() };

no cast is required and everything works fine because a B is an A.


If I do,

var hungrilyDodgy = (new[] { new A() }).Cast<B>().ToList();

the Tolist() will force enumeration and evaluation of the IEnumerable, therefore the exception will be thrown much sooner.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top