首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何动态创建Comparison<>?

如何动态创建Comparison<>?
EN

Stack Overflow用户
提问于 2011-11-12 10:18:13
回答 2查看 441关注 0票数 1

我希望通过代码中的反射创建一个比较<>-委托。我有这个:

代码语言:javascript
复制
var returnType = typeof (Int32);
var parameters = typeof(Comparison<>).GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();

AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName("MyEmissions");
AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule("MainModule", "MyEmissions.dll");

TypeBuilder tb = modBuilder.DefineType("Widget", TypeAttributes.Public);
MethodBuilder mb = tb.DefineMethod("Echo", MethodAttributes.Public | MethodAttributes.Static);

mb.SetSignature(returnType, null, null, parameters, null, null);

ILGenerator gen = mb.GetILGenerator();
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Ret);
var foo = MulticastDelegate.CreateDelegate(typeof(Comparison<>), mb);

最后一行抛出一个ArgumentException: MethodInfo必须是运行时MethodInfo对象。我是新的反射和发射,有一种感觉,只有一小步是错过了!?

编辑:

我不一定要创建一个新的程序集--我还尝试了DynamicMethod:

代码语言:javascript
复制
var returnType = typeof (Int32);
var parameters = typeof(Comparison<>).GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray();
var handler = new DynamicMethod("", returnType, parameters);
var generator = handler.GetILGenerator();

foreach (var parameter in parameters)
{
    var localVariable = generator.DeclareLocal(parameter);
    generator.Emit(OpCodes.Ldloc, localVariable);
}

if (returnType != null)
{
    var returnValue = generator.DeclareLocal(returnType);
    generator.Emit(OpCodes.Ldloc, returnValue);
}

generator.Emit(OpCodes.Ret);

handler.CreateDelegate(typeof(Comparison<>));

抛出一个BadImageFormatException :/

解决方案:

代码语言:javascript
复制
var returnType = typeof (Int32);
var methodParameters = typeof(Comparison<>).GetMethod("Invoke").GetParameters().Select(x => x.ParameterType.ToString()).ToArray();

AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName("MyEmissions");
AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule("MainModule", "MyEmissions.dll");

TypeBuilder tb = modBuilder.DefineType("Widget", TypeAttributes.Public);
MethodBuilder mb = tb.DefineMethod("Echo", MethodAttributes.Public | MethodAttributes.Static);

GenericTypeParameterBuilder[] typeParameters = mb.DefineGenericParameters(methodParameters);

mb.SetReturnType(returnType);
mb.SetParameters(typeParameters);

ILGenerator gen = mb.GetILGenerator();
gen.Emit(OpCodes.Ldnull);
gen.Emit(OpCodes.Ret);
var dt = tb.CreateType();

var mi = dt.GetMethod("Echo");
var gm = mi.MakeGenericMethod(new[] { typeof(string), typeof(string) });

var parameter = MulticastDelegate.CreateDelegate(typeof(Comparison<string>), gm);
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-11-12 13:27:01

其他人已经指出了代码中的一些错误。但是还有一个更大的问题:您正在尝试创建泛型方法和未绑定的泛型委托。

DynamicMethod的例子中,you can't create generic method at all。在动态程序集的情况下,这是可能的,但您必须使用DefineGenericParameters()

如果您设法以某种方式创建了泛型方法,则无法创建未绑定的泛型委托。也就是说,您不能像您尝试的那样创建一个类型为Comparison<T>的委托。您必须替换一些特定类型的T。因此,例如,您可以创建Comparison<int>

此外,我发现与CIL的摇摆相当困难,特别是如果你没有太多的经验。通过创建一个Expression并编译它,创建您的委托可能要容易得多。

票数 2
EN

Stack Overflow用户

发布于 2011-11-12 11:13:12

至于你的第二个例子。

你所做的是正确的。但是您发出的代码是不正确的。这就是为什么你要得到BadImageFormatException

当前,堆栈上保留的值由:

代码语言:javascript
复制
generator.Emit(OpCodes.Ldloc, localVariable);

若要进行补救,请不要加载它们或再次将它们从堆栈中弹出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8103828

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档