【问题标题】:Calling a hard-coded existing method with Reflection.Emit in .NET在 .NET 中使用 Reflection.Emit 调用硬编码的现有方法
【发布时间】:2011-11-15 00:09:03
【问题描述】:

我正在使用 Reflection.Emit-Namespace 在运行时设计一个 .NET-Type。 目前,我即将生成一个调用生成类中已经存在的方法的方法:

Dim AssemblyBuilder As AssemblyBuilder = Nothing
Dim ModuleBuilder As ModuleBuilder = Nothing
Dim TypeBuilder As TypeBuilder = Nothing

Dim MethodBuilder As MethodBuilder
Dim ReturnType As Type = Nothing

AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(New AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.RunAndSave)

ModuleBuilder = AssemblyBuilder.DefineDynamicModule("DynamicAsssembly", "DynamicAssembly.dll")
TypeBuilder = ModuleBuilder.DefineType("DynamicType")

MethodBuilder = TypeBuilder.DefineMethod("Do", MethodAttributes.Public, Nothing, Nothing)

以上工作。

MethodBuilder.GetILGenerator.EmitCall(OpCodes.Call, Me.GetType.GetMethod("DisplayString"), Nothing)
MethodBuilder.GetILGenerator.Emit(OpCodes.Ret)

ReturnType = TypeBuilder.CreateType()
Activator.CreateInstance(ReturnType)

这是我一般想做的事情:调用一个位于执行类本身的方法。但是调用下面的时候,会抛出异常。

ReturnType.GetMethod("Do").Invoke(Activator.CreateInstance(ReturnType), Nothing)

内部异常是(类似于):InvalidProgramException, "The Common Language Runtime has found an invalid program."

如果我将上面发出调用的行替换为例如

MethodBuilder.GetILGenerator.Emit(OpCodes.Ldstr, "test")
MethodBuilder.GetILGenerator.EmitCall(OpCodes.Call, GetType(System.Windows.Forms.MessageBox).GetMethod("Show", {GetType(String)}), {GetType(String)})
MethodBuilder.GetILGenerator.Emit(OpCodes.Pop)

效果很好。

我认为出现问题是因为无法访问正在执行的程序集类型及其成员,但这是真的吗?我可以更改什么来使其运行?

谢谢

陌陌

【问题讨论】:

  • DisplayString 方法的签名是什么?

标签: .net vb.net reflection reflection.emit


【解决方案1】:

DisplayString 是静态方法吗(MessageBox.Show 是)?

如果不是,您将需要一个实例来调用该方法

请给我损坏的 VB,它已经有一段时间了;)

dim fieldBuilder as FieldBuilder = typeBuilder.DefineField(
                "o", Me.GetType(),
                 FieldAttributes.InitOnly | FieldAttributes.Private);


dim constructor as ConstructorBuilder = typeBuilder.DefineConstructor(
                MethodAttributes.Public |
                MethodAttributes.HideBySig |
                MethodAttributes.SpecialName |
                MethodAttributes.RTSpecialName,
                CallingConventions.Standard, new[] { Me.GetType() });

//Make tho CTOR for the dynamic type, it needs to take an argument of the
//instance to call the method on (in this case it will be Me)

dim il as ILGenerator = constructor.GetILGenerator();

il.Emit(OpCodes.Ldarg_0);

il.Emit(OpCodes.Call, baseCtor);

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stfld, fieldBuilder);

il.Emit(OpCodes.Ret);

// Make the method
il = methodBuilder.GetILGenerator();

il.Emit(OpCodes.Ldarg, 0);
il.Emit(OpCodes.Ldfld, fieldBuilder);
il.Emit(OpCodes.Ldstr, 'test');

il.Emit(OpCodes.Callvirt, Me.GetType.GetMethod ...
il.Emit(OpCodes.Ret);

希望这会有所帮助。

了解需要发出什么的最佳方法之一是像往常一样使用编写类,然后在其上使用IL DASM,然后您可以从中复制操作码。

【讨论】:

  • 非常感谢!我确实忘记了我需要从我的班级中获取一个实例。我只是通过使其成为静态(共享)方法来尝试它并且它有效。当我有更多时间时,我会尝试调用一个实例方法。感谢 ILDASM 的提示。我已经这样做了,但我总是很难理解那里发生了什么......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 2011-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多