OfType() and Cast() with System.Type instead of Generics

We all know that whenever possible we code should be written to be type safe. But there are times when its simply not possible. Once such time we came across when putting together the Mvpc libraries behind the Ambidect Technology involved working with Cast<>() and OfType<>() with IEnumerables of unknown types.

Working with collections of known types is as simple:

var myCollection = collection.Cast();
var myCollection2 = collection.OfType();

But what do you do when all you have is a System.Type?  Sure you can try and avoid the situation but sometimes it really is bad design for the code to know the element when all it cares about is the fact we have an IEnumerable.  Yet other times the type may not even exist until it is emitted at runtime either by ourselves, or by a Json or similar library wrapping a web service.

Thanks to reflection it is possible to implement Cast(Type type) and OfType(Type type) in a cross platform way and cope with these cases when they arise.

The first thing we need is a normal generic method we can call. For Cast<>() we can define it as follows:

        private static IEnumerable CastInternal(System.Collections.IEnumerable source)
            return source.Cast();

Nothing noteworthy in that code. Now we just need a method we can pass a System.Type to. First the code then we’ll take it line by line:

        public static System.Collections.IEnumerable Cast(this System.Collections.IEnumerable source, Type elementType)
            var methodTemplate = typeof(IEnumerableExtensions_UntypedCasts).GetMethod("CastInternal", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            var genericMethod = methodTemplate.MakeGenericMethod(elementType);
            return (System.Collections.IEnumerable)genericMethod.Invoke(null, new[] { source });

This code can look very confusing if you haven’t used the System.Reflection namespace before but its actually very simple.

Line 2 uses reflection on the current type and gets the CastInternal() method we defined in the previous code block. (In the example code we’ve wrapped the extension method in a static class called IEnumerableExtensions_UntypedCasts. You will need to change the type name if you add the code to a class with a different name). At this point the MethodInfo doesn’t point to a method we can call, but a generic definition.

Line 3 uses that generic definition to create a method that can actually be called. No use of the System.Reflection.Emit namespace here so the code will run on all platforms, even those that don’t support dynamic code execution. It also means we can keep it contained in a Portable Class Library.

Line 4 invokes the newly generated method and simply returns its value.

If you add these extension methods to a static class in your own code you can then call Cast() on an IEnumerable when all you have is a System.Type of the target element type:

var type = typeof(MyType);
var collection = originalCollection.Cast(type);

The definition of OfType(System.Type) is exactly the same with the Cast<>() method swapped for OfType<>().

Hope you find them useful for those situations where you simply can’t or shouldn’t know the element type until runtime.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: