Generate call to generic method in runtime

0

Goal: generate method like this in runtime:

public void InsertOnSubmit<T>(IQueryable<T> q, T o) where T : class, new()
{
    (q as Table<T>).InsertOnSubmit(o);
}

My current code for this is:

var tb = mb.DefineType("DatabaseDataRepository");

// define & implement other methods, etc

/* Define InsertOnSubmit<> method */
var insertOnSubmitMethod = tb.DefineMethod("InsertOnSubmit",
     MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual |
                    MethodAttributes.NewSlot);
var genericInput = insertOnSubmitMethod.DefineGenericParameters("T")[0];
                genericInput.SetGenericParameterAttributes(GenericParameterAttributes.ReferenceTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint);
                insertOnSubmitMethod.SetParameters(typeof(IQueryable<>).MakeGenericType(genericInput), genericInput);
insertOnSubmitMethod.SetReturnType(null);

/* Implement InsertOnSubmit<> method */
var saveMethodGen = insertOnSubmitMethod.GetILGenerator();
saveMethodGen.Emit(OpCodes.Ldarg_1); // push first argument (collection)
saveMethodGen.Emit(OpCodes.Isinst, typeof(Table<>).MakeGenericType(genericInput)); // cast first argument to Table<>
saveMethodGen.Emit(OpCodes.Ldarg_2); // push second argument (element)
saveMethodGen.Emit(OpCodes.Callvirt, typeof(Table<>).GetMethod("InsertOnSubmit")); // insert second argument to table
saveMethodGen.Emit(OpCodes.Ret); // return from InsertOnSubmit method

But running this method on generated instance I get: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B) with stack at DatabaseDataRepository.InsertOnSubmit[T](IQueryable`1 , T )

I suspect there is something wrong in this line saveMethodGen.Emit(OpCodes.Callvirt, typeof(Table<>).GetMethod("InsertOnSubmit")); - it should really be something like typeof(Table<>).MakeGenericType(genericInput).GetMethod("InsertOnSubmit") - but this throws NotSupportedException

Any hints to tackle this? Thanks.

c#
generics
reflection.emit
asked on Stack Overflow Jul 18, 2019 by Alexander Bortnik • edited Jul 18, 2019 by Maksim Simkin

1 Answer

1

You have to use the static System.Reflection.Emit.Typebuilder.GetMethod method to create the correctly typed MethodInfo.

The msdn states:

Returns the method of the specified constructed generic type that corresponds to the specified method of the generic type definition.

In your case that would be:

Typebuilder.GetMethod(typeof(Table<>).MakeGenericType(genericInput), typeof(Table<>).GetMethod("InsertOnSubmit"))
answered on Stack Overflow Jul 18, 2019 by thehennyy

User contributions licensed under CC BY-SA 3.0