在运行时生成对泛型方法的调用
Generate call to generic method in runtime
目标:在运行时生成这样的方法:
public void InsertOnSubmit<T>(IQueryable<T> q, T o) where T : class, new()
{
(q as Table<T>).InsertOnSubmit(o);
}
我目前的代码是:
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
但是 运行 这个方法在生成的实例上我得到:
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
与堆栈 at DatabaseDataRepository.InsertOnSubmit[T](IQueryable`1 , T )
我怀疑这一行有问题 saveMethodGen.Emit(OpCodes.Callvirt, typeof(Table<>).GetMethod("InsertOnSubmit"));
- 它真的应该像 typeof(Table<>).MakeGenericType(genericInput).GetMethod("InsertOnSubmit")
- 但是这会抛出 NotSupportedException
有解决这个问题的提示吗?
谢谢。
您必须使用静态 System.Reflection.Emit.Typebuilder.GetMethod
方法来创建正确键入的 MethodInfo
。
msdn 声明:
Returns the method of the specified constructed generic type that corresponds to the specified method of the generic type definition.
你的情况是:
Typebuilder.GetMethod(typeof(Table<>).MakeGenericType(genericInput), typeof(Table<>).GetMethod("InsertOnSubmit"))
目标:在运行时生成这样的方法:
public void InsertOnSubmit<T>(IQueryable<T> q, T o) where T : class, new()
{
(q as Table<T>).InsertOnSubmit(o);
}
我目前的代码是:
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
但是 运行 这个方法在生成的实例上我得到:
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
与堆栈 at DatabaseDataRepository.InsertOnSubmit[T](IQueryable`1 , T )
我怀疑这一行有问题 saveMethodGen.Emit(OpCodes.Callvirt, typeof(Table<>).GetMethod("InsertOnSubmit"));
- 它真的应该像 typeof(Table<>).MakeGenericType(genericInput).GetMethod("InsertOnSubmit")
- 但是这会抛出 NotSupportedException
有解决这个问题的提示吗? 谢谢。
您必须使用静态 System.Reflection.Emit.Typebuilder.GetMethod
方法来创建正确键入的 MethodInfo
。
msdn 声明:
Returns the method of the specified constructed generic type that corresponds to the specified method of the generic type definition.
你的情况是:
Typebuilder.GetMethod(typeof(Table<>).MakeGenericType(genericInput), typeof(Table<>).GetMethod("InsertOnSubmit"))