2013-07-31 84 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