Accepted answer

what is the difference between ((ienumerable)source).oftype<t>() and source as ienumerable<t> for me they look similar, but they are not!

you are right. they are very different.

the former means "take the source sequence and produce a brand new, different sequence composed of all the elements of the given type from the previous sequence".

the latter means "if the runtime type of the source sequence is of the given type then give me a reference to that sequence, otherwise give me null".

let me illustrate with an example. suppose you have:

ienumerable<animal> animals = new animal[] { giraffe, tiger };
ienumerable<tiger> tigers = animals.oftype<tiger>();

that will give you back a new, different sequence that contains a single tiger.

ienumerable<mammal> mammals = animals as ienumerable<mammal>;

that will give you null. animals is not a sequence of mammals, even though it is a sequence of animals that happen to only be mammals. the actual runtime type of animals is "array of animal" and an array of animals is not type-compatible with a sequence of mammals. why not? well, suppose the conversion worked, and you then said:

animals[0] = snake;
mammal mammal = mammals.first();

and hey, you just put a snake into a variable that can only contain a mammal! we cannot allow that, so the conversion does not work.

in c# 4 you can go the other way. you can do this:

ienumerable<object> objects = animals as ienumerable<object>;

because an array of animals can be treated as a sequence of objects. you put a snake in there, and a snake is still an object. this only works in c# 4 though. (and it only works if the two types are both reference types. you cannot turn an array of int into a sequence of object.)

but the key thing to understand is that the oftype<t> method returns a brand-new sequence, and the "as" operator does a runtime type test. those are completely different things.

here's another way to look at it.

tigers = animals.oftype<tiger>() is basically the same as

tigers = animals.where(x=>x is tiger).select(x=>(tiger)x);

that is, produce a new sequence by doing a test of each member of animals to see if it is a tiger. if it is, cast it. if it is not, discard it.

mammals = animals as ienumerable<mammal> on the other hand, is basically the same as

if (animals is ienumerable<mammal>)
    mammals = (ienumerable<mammal>) animals;
    mammals = null;

make sense?


oftype<t>() will only return the types inside the enumeration that are of type t. so if you have this

object[] myobjects = new object[] { 1, 2, "hi", "there" };

then call

var mystrings = myobjects.oftype<string>();

then mystrings will be an enumerable that will skip 1 and 2 and only return you "hi" and "there". you can't cast myobjects to ienumerable<string>, because that's not what it is.

the other operator that is similar here is cast<t>(), which will attempt to cast all of the items to type t.

   var mystrings = myobjects.cast<string>();

once you start iterating over mystrings in this case, you will get a invalidcastexception, because it will try to cast 1 to a string and fail.

Related Query

More Query from same tag