Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将对象强制转换为IL中的特定类?_C#_Casting_Il - Fatal编程技术网

C# 将对象强制转换为IL中的特定类?

C# 将对象强制转换为IL中的特定类?,c#,casting,il,C#,Casting,Il,我用我正在制作的DynamicMethod发现了我得到“操作可能会破坏运行时”的原因,尽管我很容易修复了它,但它给我留下了一个看似简单的问题: 如何将类型为“object”的对象引用强制转换为特定类型,以便在对象引用上从该类型调用方法 下面是一个示例程序。在运行该方法时,它将在编译该方法时出现“操作可能会破坏运行时稳定”异常而崩溃 通过将声明为TestClass类型的变量的类型改为Object,问题得到了解决,但我仍然想知道如何将引用转换为代码中的适当类型 using System; usi

我用我正在制作的DynamicMethod发现了我得到“操作可能会破坏运行时”的原因,尽管我很容易修复了它,但它给我留下了一个看似简单的问题:

  • 如何将类型为“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问题。谢谢你的努力。