blogs.conchango.com

welcome to the conchango blogging site
Welcome to blogs.conchango.com Sign in | Join | Help
in Search

John Rayner's Blog

Brain.Extract<IBloggable>( Where.Author.Is( "John.Rayner" ) );

Reflection on Generic Types (part 2)

Some time ago I posted a question about reflection on generics.  This remained unanswered until Anthony recently posted the solution in a comment.  To reiterate what was said in there:

The Question

I have a generic interface ICustomDataMapper<T>.  I want to know, programatically, if a Type t which has been passed to my method implements this interface, or at least a closed version thereof.  The best I could come up with was:

bool DoesImplement = false;
foreach (Type intface in t.GetInterfaces())
{
     if (intface.IsGenericType &&
        intface.GetGenericTypeDefinition().Name.StartsWith
              
("ICustomDataMapper"))
     DoesImplement =
true;
}

This is a bit rubbish.  Can anyone show me a better way?

Anthony's Solution

Anthony suggested instantiating a concrete version of the generic type to relfect over it.  This doesn't work too well with interfaces, but a simple modification gets it to work as follows:

bool DoesImplement = false;
Type GenericBase = typeof(ICustomDataMapper<string>).GetGenericTypeDefinition();
foreach (Type intface in t.GetInterfaces())
{
     if (intface.IsGenericType &&
        intface.GetGenericTypeDefinition() == GenericBase)

     DoesImplement =
true;
}

Yet Another Way

This prompted some further investigation and I found out that there are two other ways to access the generic type:

Type GenericBase = Type.GetType("MyProject.DataMapping.ICustomDataMapper`1");

Although it works, this is back to being a bit rubbish becuase the type name is coded in a string so there is no compile-time checking.  Also we need to use the fully qualified type name.  However, the following also works and gets around these problems:

Type GenericBase = typeof( ICustomDataMapper<> );

I think that this has to be the neatest solution. 

An Unrelated Aside

As per Anthony's comment, the number after the backtick ( ` ) relates to the number of generic type parameters on the definition.  This means that a generic type with two parameters is completely unrelated to one with only one, even if they share the same name.  Or to put it another way, the following two definitions can be in the same namespace:

public interface IGeneric<T>
{
    T DoSomething(T t);
}

public interface IGeneric<K, V>
{
    K DoSomethingElse(V v);
}

A type can then implement both of these interfaces, as in:

public class Concrete: IGeneric<Concrete>, IGeneric<string, Concrete>

Published 02 November 2006 09:59 by john.rayner

Comments

 

IanBru said:

So I recently had reason to approach this problem again when trying to parse form fields into generic arrays, I went searching for how to do it and found this rather old block post (but nothing newer)

I found this approach which you might find preferable to the above, using IsAssignableFrom instead of iterating through base classes.

//Is it a generic collection object (ie a ICollection<T>?)

bool IsGenericCollection(type T)

{

return type.IsGenericType && (typeof(ICollection<>).MakeGenericType(type.GetGenericArguments())).IsAssignableFrom(type))

}

July 28, 2008 11:08
Anonymous comments are disabled
Powered by Community Server (Personal Edition), by Telligent Systems