views:

234

answers:

3

I have a marker interface defined as

public interface IExtender<T>
{
}

I have a class that implements IExtender

public class UserExtender : IExtender<User>

At runtime I recieve the UserExtender type as a parameter to my evaluating method

public Type Evaluate(Type type) // type == typeof(UserExtender)

How do I make my Evaluate method return

typeof(User)

based on the runtime evaluation. I am sure reflection is involved but I can't seem to crack it.

(I was unsure how to word this question. I hope it is clear enough.)

+1  A: 

There is an example of doing what you describe in the MSDN documentation for the GetGenericTypeDefinition method. It uses the GetGenericArguments method.

Type[] typeArguments = t.GetGenericArguments();
Console.WriteLine("\tList type arguments ({0}):", typeArguments.Length);
foreach (Type tParam in typeArguments)
{
    Console.WriteLine("\t\t{0}", tParam);
}

In your example I think you would want to replace t with this. If that doesn't work directly you may need to do something with the GetInterfaces method to enumerate the current interfaces on your type and then GetGenericArguments() from the interface type.

spoon16
+1  A: 

I went this way based on some of the tidbits provided. It could be made more robust to handle multiple generic arguments on the interface.... but I didn't need it to ;)

private static Type SafeGetSingleGenericParameter(Type type, Type interfaceType)
    {
        if (!interfaceType.IsGenericType || interfaceType.GetGenericArguments().Count() != 1)
            return type;

        foreach (Type baseInterface in type.GetInterfaces())
        {
            if (baseInterface.IsGenericType &&
                baseInterface.GetGenericTypeDefinition() == interfaceType.GetGenericTypeDefinition())
            {
                return baseInterface.GetGenericArguments().Single();
            }
        }

        return type;
    }
berko
+1  A: 

I read your question completely differently than the other answers.

If the evaluate signature can be changed to:

public Type Evaluate<T>(IExtender<T> it)
{
    return typeof(T);
}

This doesn't require the calling code to change, but does require the parameter to be of type IExtender<T>, however you can easily get at the type T :

// ** compiled and tested    
UserExtender ue = new UserExtender();
Type t = Evaluate(ue);

Certainly it's not as generic as something just taking a Type parameter, but this is a different take on the problem. Also note that there are Security Considerations for Reflection [msdn]

Robert Paulson