首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DynamicMethod和类型检查

DynamicMethod和类型检查
EN

Stack Overflow用户
提问于 2013-07-31 21:25:50
回答 2查看 482关注 0票数 9

有人可以解释或指出为什么运行时类型检查不发生在示例中-字符串属性可以设置为任何类型值...

在非常意想不到的地方坚持了下来,真的很惊讶

代码语言:javascript
复制
using System;
using System.Reflection;
using System.Reflection.Emit;

namespace Dynamics
{
internal class Program
    {
    private static void Main(string[] args)
    {
        var a = new A();
        a.Name = "Name";
        Console.WriteLine(a.Name.GetType().Name);

        PropertyInfo pi = a.GetType().GetProperty("Name");          

        DynamicMethod method = new DynamicMethod(
                "DynamicSetValue", // NAME
                null, // return type
                new Type[] 
                            {
                                typeof(object), // 0, objSource
                                typeof(object), // 1, value
                            }, // parameter types
                typeof(Program), // owner
                true); // skip visibility

        ILGenerator gen = method.GetILGenerator();
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
        gen.Emit(OpCodes.Ret);

        SetValue setMethod = (SetValue)method.CreateDelegate(typeof(SetValue));

        int val = 123;
        setMethod(a, val);
        Console.WriteLine(a.Name.GetType().Name);

        A anotherA = new A();
        anotherA.Name = "Another A";
        setMethod(a, anotherA);
        Console.WriteLine(a.Name.GetType().Name);
    }
}

public class A
{
    public string Name { get; set; }
}

public delegate void SetValue(object obj, object val);
}
EN

回答 2

Stack Overflow用户

发布于 2014-06-17 23:40:11

我做了一个小实验:在你的类中添加了一个方法:

代码语言:javascript
复制
    static void SetValue1(A a, object v)
    {
        a.Name = (string)v;
    }

当然,做SetValue1(a, 123);会抛出InvalidCastException。然后我使用ildasm.exe反汇编了代码。SetValue1看起来像这样:

代码语言:javascript
复制
.method private hidebysig static void  SetValue1(class ConsoleApplication2.A a,
                                                   object v) cil managed
  {
    // Code size       15 (0xf)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldarg.1
    IL_0003:  castclass  [mscorlib]System.String // <--- replace this with nop
    IL_0008:  callvirt   instance void ConsoleApplication2.A::set_Name(string)
    IL_000d:  nop
    IL_000e:  ret
  } // end of method Program::SetValue1

好的,让我们用nop替换强制转换的castclass [mscorlib]System.String,并用ilasm.exe重新编译。

现在,使用错误类型的参数调用SetValue1并产生与动态方法相同的结果。因此,在这种情况下,CLR似乎没有进行类型检查。documentation说:

在即时编译期间,一个可选的验证过程会检查要即时编译为本机代码的方法的元数据和微软中间语言(MSIL),以验证它们是否是类型安全的。如果代码具有绕过验证的权限,则跳过此过程。

在这种情况下,我们在本地机器上运行代码,所以CLR相信IL是有效的。

您可以通过对输出.exe文件运行peverify.exe来手动验证程序集。它将返回一个错误:Program::SetValue1][offset 0x00000004][found ref 'System.Object'][expected ref 'System.String'] Unexpected type on the stack.

有一篇很好的帖子探讨了这个话题:http://www.pcreview.co.uk/forums/net-type-safety-and-net-configuration-tool-t1225543.html

票数 2
EN

Stack Overflow用户

发布于 2013-07-31 22:17:10

我认为这是因为您将参数声明为object(System.Object)。intSystem.ValueType:System.ObjectA:System.ObjectSystem.Object是所有类(http://msdn.microsoft.com/en-us/library/system.object.aspx)的基类。例如,如果您将typeof(object)更改为typeof(string),您将得到强制转换错误。

编辑:我认为您的示例中禁用了params类型检查,因为您替换了对getter/setter属性的调用。如果您需要对调用动态方法进行类型检查,您可以尝试使用以下代码:

代码语言:javascript
复制
    var a = new A();
    a.Name = "Name";
    Console.WriteLine(a.Name.GetType().Name);

    PropertyInfo pi = a.GetType().GetProperty("Name");          

    DynamicMethod method = new DynamicMethod(
            "DynamicSetValue", // NAME
            null, // return type
            new Type[] 
                        {
                            typeof(Object), // 0, objSource
                            pi.PropertyType, // 1, value
                        }, // parameter types
            typeof(OracleUserOlapRepositoryTests), // owner
            true); // skip visibility

    ILGenerator gen = method.GetILGenerator();
    gen.Emit(OpCodes.Ldarg_0);
    gen.Emit(OpCodes.Ldarg_1);
    gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
    gen.Emit(OpCodes.Ret);

   //correct  
   method.Invoke(a, new object[]{a,"test"});

   //error  
   method.Invoke(a, new object[]{a,new List<String>()});

   Console.WriteLine(a.Name.GetType().Name);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17971700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档