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 because 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>

November 2 2006
blog comments powered by Disqus