2013-07-31 45 views
9

有人能解释或指向解释为什么运行时类型检查不低于样品发生 - 字符串属性可以设置为任何类型的值...
非常意想不到的地方有这样闷和真的很惊讶DynamicMethod的和类型检查

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

回答

0

我认为它是因为你声明params为objectSystem.Object)。 intSystem.ValueType:System.ObjectA:System.ObjectSystem.Object是所有类的基类(http://msdn.microsoft.com/en-us/library/system.object.aspx)。例如,如果您将typeof(object)更改为typeof(string),则会发生转换错误。

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

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

其实我预计分配给A.Name一定的价值,而不是通过方法参数打字时类型检查。 pi.SetValue(a,123)将导致带有关于对象类型转换错误的文本的ArgumentException,但SetValue方法也接受对象作为参数。 –

+0

实际上发生参考更改没有类型检查... –

2

我做了一个小实验:添加一个方法到类:

static void SetValue1(A a, object v) 
    { 
     a.Name = (string)v; 
    } 

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

.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 

好吧,让我们更换投castclass [mscorlib]System.Stringnopilasm.exe重新编译。

现在,对具有错误类型参数的SetValue1的调用会通过并产生与动态方法相同的结果。所以看起来CLR在这种情况下并没有进行类型检查。 的documentation说:

During just-in-time (JIT) compilation, an optional verification process examines the metadata and Microsoft intermediate language (MSIL) of a method to be JIT-compiled into native machine code to verify that they are type safe. This process is skipped if the code has permission to bypass verification.

在这种情况下,我们运行的本地机器上的代码,所以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

+0

这是正确的,一个很好的证明。 JIT对无法验证的IL没有根本性问题。 – usr