Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Reflection - MakeGenericType for recursive type parameters

At some place of my project I need to make a concrete generic type, taking as arguments a generic type definition (with a single parameter) and a type of that parameter.

For this purpose I've written a method, which is pretty simple:

Type MakeGenericType(Type definition, Type parameter)
{
    return definition.MakeGenericType(parameter);
}

However, at some point, I need to create a type, say, List<List<T>> with given element type T. Although I'm able to create a type List<List<T>> using my method, subsequent attempt to make a concrete type List<List<int>> from it fails - see code below:

var genericList = MakeGenericType(typeof(List<>), typeof(List<>)); // success

MakeGenericType(genericList, typeof(int)); // exception

An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll

Additional information: System.Collections.Generic.List`1[System.Collections.Generic.List`1[T]] is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true.

Moreover, following call won't even compile:

MakeGenericType(typeof(List<List<>>), typeof(int));

I've checked this question regarding difference between IsGenericTypeDefinition and ContainsGenericParameters. However, I still don't have an idea, how to deal with type objects like genericList.

Apparently, using reflection I can construct a type object, which is nothing to do about it - that's very confusing to me.

So the question is, how can I create a concrete type from a generic, which contains generic type definition as a parameter? Is it possible at all?

like image 590
stop-cran Avatar asked Dec 19 '25 20:12

stop-cran


1 Answers

You need to decompose the passed type to generic type definitions and build the resulting generic type bottom up using something like this:

static Type MakeGenericType(Type definition, Type parameter)
{
    var definitionStack = new Stack<Type>();
    var type = definition;
    while (!type.IsGenericTypeDefinition)
    {
        definitionStack.Push(type.GetGenericTypeDefinition());
        type = type.GetGenericArguments()[0];
    }
    type = type.MakeGenericType(parameter);
    while (definitionStack.Count > 0)
        type = definitionStack.Pop().MakeGenericType(type);
    return type;
}
like image 95
Ivan Stoev Avatar answered Dec 21 '25 12:12

Ivan Stoev