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);
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.