Reflection.Emit:为具有 GenericTypeParameterBuilder 类型参数的构造类型获取 MethodInfo
Reflection.Emit: Get a MethodInfo for a constructed type having GenericTypeParameterBuilder type parameter
我正在尝试 Reflection.Emit
一个通用的 class,它实现了一个使用 class 的通用参数构造的通用接口,例如这个:
class Foo<U>: IEquatable<U>
{
bool IEquatable<U>.Equals(U other) { /* ... */ }
}
我正在努力为 IEquatable<U>.Equals(U)
方法获取 MethodInfo
。
反映构造类型 IEquatable<U>
抛出一个 NotSupportedException
因为 U
是一个 GenericTypeParameterBuilder
,而 TypeBuilder.GetMethod(IEquatable<U>, IEquatable<T>.Equals(T))
returns 一个奇怪的 IEquatable<U>.Equals(T)
方法。
感谢任何帮助!
测试代码:
// define class Foo<U>
var tb = moduleBuilder.DefineType("Foo");
var genParams = tb.DefineGenericParameters("U");
// IEquatable<T>.Equals(T) method
var miEqualsT = typeof(IEquatable<>).GetMethod("Equals", typeof(IEquatable<>).GetGenericArguments());
// IEquatable<U> constructed type
var iEquatableU = typeof(IEquatable<>).MakeGenericType(genParams);
// now trying to get IEquatable<U>.Equals(U) method
MethodInfo miEqualsU;
try { miEqualsU = iEquatableU.GetMethod("Equals", genParams); }
catch (NotSupportedException) { Console.WriteLine("Reflecting constructed interface not supported."); }
miEqualsU = TypeBuilder.GetMethod(iEquatableU, miEqualsT);
var declaringType =$"{miEqualsU.DeclaringType.Name}<{miEqualsU.DeclaringType.GenericTypeArguments[0].Name}>";
var parameterType = miEqualsU.GetParameters()[0].ParameterType;
Console.WriteLine($"TypeBuilder.GetMethod() returns {declaringType}.{miEqualsU.Name}({parameterType.Name})");
// OUTPUT:
// Reflecting constructed interface not supported.
// TypeBuilder.GetMethod() returns IEquatable`1<U>.Equals(T)
您已经掌握了 miEqualsT
的正确方法。以下是使用方法实现接口的方法:
var assemblyName = new AssemblyName { Name = "asd" };
var moduleBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run).DefineDynamicModule(assemblyName.Name);
var tb = moduleBuilder.DefineType("Foo");
var genParams = tb.DefineGenericParameters("U");
var miEqualsT = typeof(IEquatable<>).GetMethod("Equals", typeof(IEquatable<>).GetGenericArguments());
var myMethod = tb.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.Virtual, typeof(bool), genParams);
var il = myMethod.GetILGenerator();
il.Emit(OpCodes.Ldstr, "I was invoked!");
il.Emit(OpCodes.Call, GetMethod<string>(a => Console.WriteLine(a)));
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ret);
tb.AddInterfaceImplementation(typeof(IEquatable<>).MakeGenericType(genParams));
tb.DefineMethodOverride(myMethod, miEqualsT);
var t = tb.CreateType();
//Hack for demonstration
private MethodInfo GetMethod<T>(Expression<Action<T>> thing)
{
return ((thing as LambdaExpression).Body as MethodCallExpression).Method;
}
然后使用它:
var genericType = t.MakeGenericType(typeof(int));
var tObj = Activator.CreateInstance(genericType);
var method = genericType.GetMethods()
.Where(m => m.Name == "Equals" && m.DeclaringType == genericType)
.First();
method.Invoke(tObj, new object[] { 5 });
或:
var tObj = Activator.CreateInstance(genericType);
DoIt(tObj as IEquatable<int>);
private void DoIt(IEquatable<int> obj)
{
obj.Equals(5);
}
我正在尝试 Reflection.Emit
一个通用的 class,它实现了一个使用 class 的通用参数构造的通用接口,例如这个:
class Foo<U>: IEquatable<U>
{
bool IEquatable<U>.Equals(U other) { /* ... */ }
}
我正在努力为 IEquatable<U>.Equals(U)
方法获取 MethodInfo
。
反映构造类型 IEquatable<U>
抛出一个 NotSupportedException
因为 U
是一个 GenericTypeParameterBuilder
,而 TypeBuilder.GetMethod(IEquatable<U>, IEquatable<T>.Equals(T))
returns 一个奇怪的 IEquatable<U>.Equals(T)
方法。
感谢任何帮助!
测试代码:
// define class Foo<U>
var tb = moduleBuilder.DefineType("Foo");
var genParams = tb.DefineGenericParameters("U");
// IEquatable<T>.Equals(T) method
var miEqualsT = typeof(IEquatable<>).GetMethod("Equals", typeof(IEquatable<>).GetGenericArguments());
// IEquatable<U> constructed type
var iEquatableU = typeof(IEquatable<>).MakeGenericType(genParams);
// now trying to get IEquatable<U>.Equals(U) method
MethodInfo miEqualsU;
try { miEqualsU = iEquatableU.GetMethod("Equals", genParams); }
catch (NotSupportedException) { Console.WriteLine("Reflecting constructed interface not supported."); }
miEqualsU = TypeBuilder.GetMethod(iEquatableU, miEqualsT);
var declaringType =$"{miEqualsU.DeclaringType.Name}<{miEqualsU.DeclaringType.GenericTypeArguments[0].Name}>";
var parameterType = miEqualsU.GetParameters()[0].ParameterType;
Console.WriteLine($"TypeBuilder.GetMethod() returns {declaringType}.{miEqualsU.Name}({parameterType.Name})");
// OUTPUT:
// Reflecting constructed interface not supported.
// TypeBuilder.GetMethod() returns IEquatable`1<U>.Equals(T)
您已经掌握了 miEqualsT
的正确方法。以下是使用方法实现接口的方法:
var assemblyName = new AssemblyName { Name = "asd" };
var moduleBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run).DefineDynamicModule(assemblyName.Name);
var tb = moduleBuilder.DefineType("Foo");
var genParams = tb.DefineGenericParameters("U");
var miEqualsT = typeof(IEquatable<>).GetMethod("Equals", typeof(IEquatable<>).GetGenericArguments());
var myMethod = tb.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.Virtual, typeof(bool), genParams);
var il = myMethod.GetILGenerator();
il.Emit(OpCodes.Ldstr, "I was invoked!");
il.Emit(OpCodes.Call, GetMethod<string>(a => Console.WriteLine(a)));
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ret);
tb.AddInterfaceImplementation(typeof(IEquatable<>).MakeGenericType(genParams));
tb.DefineMethodOverride(myMethod, miEqualsT);
var t = tb.CreateType();
//Hack for demonstration
private MethodInfo GetMethod<T>(Expression<Action<T>> thing)
{
return ((thing as LambdaExpression).Body as MethodCallExpression).Method;
}
然后使用它:
var genericType = t.MakeGenericType(typeof(int));
var tObj = Activator.CreateInstance(genericType);
var method = genericType.GetMethods()
.Where(m => m.Name == "Equals" && m.DeclaringType == genericType)
.First();
method.Invoke(tObj, new object[] { 5 });
或:
var tObj = Activator.CreateInstance(genericType);
DoIt(tObj as IEquatable<int>);
private void DoIt(IEquatable<int> obj)
{
obj.Equals(5);
}