Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get generic argument types of generic type from derived type in c#

Tags:

c#

reflection

Supose i have:

class MyBase<T1, T2>{}

class MyConcreteBase<T2> : MyBase<ConcreteType1, T2>{}

class MyConcrete1 : MyConcreteBase<ConcreteType2>{}

class MyConcrete2 : MyBase<ConcreteType1, ConcreteType2>{}

How do i get types of T1 and T2 if i have instance of MyConcrete1 or MyConcrete2 or MyConcreteBase or any other instance of type derived from MyBase<T1, T2>

The way i do it now is i'm "getting up" by inheritance chain using .GetType().BaseType while BaseType.Name.StartsWith("MyBase") and then using .GetGenericArguments()

It is working, but i'm not satisfied with it, especially .StartsWith("MyBase") part.

Anyone have other suggestions?

like image 428
Andrej Slivko Avatar asked May 30 '11 15:05

Andrej Slivko


People also ask

Is it possible to inherit from a generic type?

An attribute cannot inherit from a generic class, nor can a generic class inherit from an attribute.

What is generic type arguments?

The generic argument list is a comma-separated list of type arguments. A type argument is the name of an actual concrete type that replaces a corresponding type parameter in the generic parameter clause of a generic type. The result is a specialized version of that generic type.

Where is generic type constraint?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.


2 Answers

You can walk up the inheritance hierarchy and look for a GenericType, which is constructed from BaseType<,>. Try:

var type = c.GetType();
Type baseType = type;
while(null != (baseType = baseType.BaseType)) 
{
    if (baseType.IsGenericType) 
    {
        var generic = baseType.GetGenericTypeDefinition();
        if (generic == typeof(MyBase<,>)) 
        {
            var genericTypes = baseType.GetGenericArguments();
            // genericTypes has the type argument used to construct baseType.
            break;
        }
    }
}   
like image 128
driis Avatar answered Oct 31 '22 22:10

driis


Yeah, don't use string parsing. You can simply use BaseType.IsAssignableFrom(typeof(MyBase<,>)) (might have to reverse the BaseType and MyBase<,> -- I always get that confused).

It might also be easier to expose the types as properties in your base class, e.g.:

public Type T1_Type { get { return typeof(T1); } }
public Type T2_Type { get { return typeof(T2); } }

I do have to ask, why do you need to extract these type parameters? This is a code smell to me.

EDIT: I should add that you can't use IsAssignableFrom as is for generics. Check out this answer for a full solution: How To Detect If Type is Another Generic Type

like image 35
siride Avatar answered Oct 31 '22 21:10

siride