C# 将对象强制转换为IL中的特定类?
我用我正在制作的DynamicMethod发现了我得到“操作可能会破坏运行时”的原因,尽管我很容易修复了它,但它给我留下了一个看似简单的问题:C# 将对象强制转换为IL中的特定类?,c#,casting,il,C#,Casting,Il,我用我正在制作的DynamicMethod发现了我得到“操作可能会破坏运行时”的原因,尽管我很容易修复了它,但它给我留下了一个看似简单的问题: 如何将类型为“object”的对象引用强制转换为特定类型,以便在对象引用上从该类型调用方法 下面是一个示例程序。在运行该方法时,它将在编译该方法时出现“操作可能会破坏运行时稳定”异常而崩溃 通过将声明为TestClass类型的变量的类型改为Object,问题得到了解决,但我仍然想知道如何将引用转换为代码中的适当类型 using System; usi
- 如何将类型为“object”的对象引用强制转换为特定类型,以便在对象引用上从该类型调用方法
TestClass
类型的变量的类型改为Object
,问题得到了解决,但我仍然想知道如何将引用转换为代码中的适当类型
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();
}
}
}
在代码中,我用星号标记了一行。我可以在该点发出什么样的代码,使堆栈上的对象
引用变为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();
}
}
}
使用系统;
使用System.Reflection.Emit;
命名空间控制台应用程序9
{
公共类TestClass
{
public void TestMethod(){}
}
班级计划
{
静态void Main(字符串[]参数)
{
Type Type=typeof(TestClass);
DynamicMethod=newdynamicmethod(“”,typeof(Object),null);
ILGenerator il=method.GetILGenerator();
LocalBuilder变量=il.DeclareLocal(typeof(Object));
//构造对象
Emit(opcode.Newobj,type.GetConstructor(新类型[0]);
il.Emit(opcode.Stloc,变量);
//呼叫测试方法
il.Emit(opcode.Ldloc,变量);
//我在这里做什么?
Emit(opcode.Call,type.GetMethod(“TestMethod”);
//返回对象
il.Emit(opcode.Ldloc,变量);
发射(操作码Ret);
//创建并调用委托
Func fn=(Func)method.CreateDelegate(
类型(Func));
对象实例=fn();
}
}
}
简短的回答:
// Call Test method
il.Emit(OpCodes.Ldloc, variable);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Call, type.GetMethod("TestMethod"));
那怎么可能呢?嗯,我用的方法是。首先,写一个你想做的方法。我得出了以下结论:
private static object PrecompiledTest()
{
object variable = new TestClass();
((TestClass) variable).TestMethod();
return variable;
}
.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
}
现在,编译它,打开Reflector,打开您的程序集。导航到您的函数并查看它的MSIL。上述函数反编译为以下内容:
private static object PrecompiledTest()
{
object variable = new TestClass();
((TestClass) variable).TestMethod();
return variable;
}
.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
在您的示例中确实有效。最后一件事,当我们讨论反射器的话题时。您可以使用addin非常有效地为您生成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;
}
很抱歉这么长时间忽略了你的答案,我的代码中有一个bug,这使得Castclass看起来不是正确的选择,但当我发现这一点时,我立刻忘记了我的so问题。谢谢你的努力。