在 .NET 中使用 Reflection.Emit 调用硬编码的现有方法

发布于 2024-12-15 16:14:28 字数 1733 浏览 1 评论 0原文

我正在使用 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,“公共语言运行时发现了一个无效程序。”

如果我用例如替换上面发出呼叫的行,

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)

它就可以正常工作。

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

谢谢莫莫

I'm designing a .NET-Type at runtime by using the Reflection.Emit-Namespace.
Currently, I'm about to generate a method which invokes an already existing method in the generating class:

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)

The above works.

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

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

This is want I want to do in general: Invoking a method which is located in the executing class itself. But when calling the following, an exeception is thrown.

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

The inner exception is (something like): InvalidProgramException, "The Common Language Runtime has found an invalid program."

If I replace the lines from above in which I emit the call by e.g.

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)

it works fine.

I suppose there occures a problem because the executing assembly types and their members are not accessible, but is that true, and what may I change to get it running?

Thanks

Momo

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

余生一个溪 2024-12-22 16:14:29

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,然后您可以从中复制操作码。

Is DisplayString a static method (MessageBox.Show is)?

If not you are going to need an instance to call the method on

please for give my mangeled VB, its been quite a while ;)

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);

hope this helps.

One of the best ways to learn what need to emit is to use write the class as you normally would, then use IL DASM on it, then you can copy the OpCodes from that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文