gpt4 book ai didi

c# - 将对象转换为 IL 中的特定类?

转载 作者:太空狗 更新时间:2023-10-29 22:21:02 25 4
gpt4 key购买 nike

我发现了我在生成的 DynamicMethod 中出现“操作可能会破坏运行时稳定性”的原因,虽然我很容易修复它,但它给我留下了一个看似简单的问题:

  • 如何将类型为“Object”的对象引用转换为特定类型,以便我可以在对象引用上调用该类型的方法?

下面是一个示例程序。运行它时,它会在编译方法时崩溃并出现“Operation could destabilize the runtime”异常。

只需将声明的变量类型更改为类型 TestClass 而不是 Object 即可解决问题,但我仍然想知道如何转换对代码中适当类型的引用。

在代码中我用星号标记了一行。那时我可以发出什么代码,使堆栈上的 Object 引用变成 TestClass 引用,以便方法调用能够通过?

请注意,我知道是方法调用产生了问题,如果我完全注释掉这些行,则变量是哪种类型并不重要,该方法已编译并执行得很好。

这是代码。

using System;
using System.Reflection.Emit;

namespace ConsoleApplication9
{
public class TestClass
{
public void TestMethod() { }
}

class Program
{
static void Main(string[] args)
{
Type type = typeof(TestClass);
DynamicMethod method = new DynamicMethod("", typeof(Object), null);
ILGenerator il = method.GetILGenerator();
LocalBuilder variable = il.DeclareLocal(typeof(Object));

// Construct object
il.Emit(OpCodes.Newobj, type.GetConstructor(new Type[0]));
il.Emit(OpCodes.Stloc, variable);

// Call Test method
il.Emit(OpCodes.Ldloc, variable);
// ***************************************** what do I do here?
il.Emit(OpCodes.Call, type.GetMethod("TestMethod"));

// Return object
il.Emit(OpCodes.Ldloc, variable);
il.Emit(OpCodes.Ret);

// Create and call delegate
Func<Object> fn = (Func<Object>)method.CreateDelegate(
typeof(Func<Object>));
Object instance = fn();
}
}
}

最佳答案

简短的回答:

// Call Test method
il.Emit(OpCodes.Ldloc, variable);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Call, type.GetMethod("TestMethod"));

那是怎么来的呢?嗯,我用的方法是Reflector .首先,写一个方法来做你想做的事。我想出了以下内容:

private static object PrecompiledTest()
{
object variable = new TestClass();
((TestClass) variable).TestMethod();
return variable;
}

现在,编译它,打开 Reflector,然后打开你的程序集。导航到您的函数并查看它的 MSIL。上面的函数反编译如下:

.method private hidebysig static object PrecompiledTest() cil managed
{
.maxstack 1
.locals init (
[0] object variable,
[1] object CS$1$0000)
L_0000: nop
L_0001: newobj instance void EmitTest.TestClass::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: castclass EmitTest.TestClass
L_000d: callvirt instance void EmitTest.TestClass::TestMethod()
L_0012: nop
L_0013: ldloc.0
L_0014: stloc.1
L_0015: br.s L_0017
L_0017: ldloc.1
L_0018: ret
}

上面使用callvirt代替call。我并不是真的那么精通 IL,所以我不确定其中的区别,但是 call 在您的示例中确实有效。最后一件事,当我们讨论 Reflector 的话题时。您可以使用 ReflectionEmitLanguage插件可以很好地为您生成 Emit 代码。此插件为您生成以下代码:

public MethodBuilder BuildMethodPrecompiledTest(TypeBuilder type)
{
// Declaring method builder
// Method attributes
System.Reflection.MethodAttributes methodAttributes =
System.Reflection.MethodAttributes.Private
| System.Reflection.MethodAttributes.HideBySig
| System.Reflection.MethodAttributes.Static;
MethodBuilder method = type.DefineMethod("PrecompiledTest", methodAttributes);
// Preparing Reflection instances
ConstructorInfo ctor1 = typeof(TestClass).GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
},
null
);
MethodInfo method2 = typeof(TestClass).GetMethod(
"TestMethod",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
new Type[]{
},
null
);
// Setting return type
method.SetReturnType(typeof(Object));
// Adding parameters
ILGenerator gen = method.GetILGenerator();
// Preparing locals
LocalBuilder variable = gen.DeclareLocal(typeof(Object));
LocalBuilder CS$1$0000 = gen.DeclareLocal(typeof(Object));
// Preparing labels
Label label23 = gen.DefineLabel();
// Writing body
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Newobj,ctor1);
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Castclass,TestClass);
gen.Emit(OpCodes.Callvirt,method2);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Stloc_1);
gen.Emit(OpCodes.Br_S,label23);
gen.MarkLabel(label23);
gen.Emit(OpCodes.Ldloc_1);
gen.Emit(OpCodes.Ret);
// finished
return method;
}

关于c# - 将对象转换为 IL 中的特定类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1558866/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com