Search code examples
c#.net-corereflection.emit

How to use a generic type with a runtime-defined type parameter in Reflection.Emit


Running this under .NET 8.

IJoinable<T1, T2> already exists in the codebase as a generic interface. It declares one method, T2 Join(T1 value). The types being used for the type parameters (lType, rType, joinedType) are TypeBuilder variables that have been dynamically generated at runtime.

    var joinType = typeof(IJoinable<,>).MakeGenericType(rType, joinedType);
    lType.AddInterfaceImplementation(joinType);
    var joinMethod = lType.DefineMethod("Join", MethodAttributes.Public | MethodAttributes.Virtual, joinedType, [rType]);
    var gen = joinMethod.GetILGenerator();
    gen.Emit(OpCodes.Ldarg_0);
    gen.Emit(OpCodes.Ldarg_1);
    gen.Emit(OpCodes.Call, ctor);
    gen.Emit(OpCodes.Ret);
    lType.DefineMethodOverride(joinMethod, joinType.GetMethod("Join")!);

When I call joinType.GetMethod() on that last line, it throws NotSupportedException, because somehow it ended up inside of System.Reflection.Emit.TypeBuilderInstantiation.GetMethodImpl(), whose entire method body is to throw NotSupportedException.

If that doesn't work, what's the right way to do this?


Solution

  • To perform operations involving Reflection.Emit and generics, there are three somewhat hidden, yet in plain sight, static methods on TypeBuilder:

    • TypeBuilder.GetMethod
    • TypeBuilder.GetConstructor
    • TypeBuilder.GetField

    These methods operate on TypeBuilderInstantiation objects. Therefore, the call that fails using the classic GetMethod method needs to be replaced with one like this:

    var genericMethod = TypeBuilder.GetMethod(joinType, typeof(IJoinable<,>).GetMethod("Join"));

    Actually, I think the documentation for these methods is quite good (TypeBuilder.GetMethod). However, they deviate from the pattern established by other parts of the Reflection.Emit API, making them somewhat difficult to find.