2011-12-07 29 views
1

在我的Silverlight客戶端上,我在運行時生成一個類以將其綁定到數據網格。我正在使用基於this博客文章的方法。 現在我想通過調用屬性設置器中的ValidateProperty來使用datagrid cellvalidation。但是由於屬性是在運行時生成的,我需要在Reflection.Emit中執行此操作。如何在屬性設置器中發送驗證代碼

這是C#我想在IL生成:

public int TestProperty 
    { 
     get { return testProperty; } 
     set 
     { 
      Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "TestProperty" }); 
      testProperty = value; 
     } 
    } 

這是這種方法在IL反編譯如何ILspy:

.property int32 TestProperty 
{ 
    .get public hidebysig specialname 
     instance int32 get_TestProperty() cil managed 
    { 
     // Method begins at RVA 0x224c 
     // Code size 12 (0xc) 
     .maxstack 1 
     .locals init (
      [0] int32 
     ) 

     IL_0000: nop 
     IL_0001: ldarg.0 
     IL_0002: ldfld int32 class SilverlightApplication2.testclass::testProperty 
     IL_0007: stloc.0 
     IL_0008: br.s IL_000a 
     IL_000a: ldloc.0 
     IL_000b: ret 
    } // End of method testclass.get_TestProperty 
    .set public hidebysig specialname 
     instance void set_TestProperty (
      int32 value 
     ) cil managed 
    { 
     // Method begins at RVA 0x2264 
     // Code size 43 (0x2b) 
     .maxstack 5 
     .locals init (
      [0] class [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext 
     ) 

     IL_0000: nop 
     IL_0001: ldarg.1 
     IL_0002: box int32 
     IL_0007: ldarg.0 
     IL_0008: ldnull 
     IL_0009: ldnull 
     IL_000a: newobj instance void [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext::.ctor(object, class [mscorlib]System.IServiceProvider, class [mscorlib]System.Collections.Generic.IDictionary`2<object, object>) 
     IL_000f: stloc.0 
     IL_0010: ldloc.0 
     IL_0011: ldstr "TestProperty" 
     IL_0016: callvirt instance void [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext::set_MemberName(string) 
     IL_001b: nop 
     IL_001c: ldloc.0 
     IL_001d: call void [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.Validator::ValidateProperty(object, class [System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext) 
     IL_0022: nop 
     IL_0023: ldarg.0 
     IL_0024: ldarg.1 
     IL_0025: stfld int32 class SilverlightApplication2.testclass::testProperty 
     IL_002a: ret 
    } // End of method testclass.set_TestProperty 
} 

,這是我試圖把它寫在反思。 Emit:

 setIL.Emit(OpCodes.Ldarg_1); 
     setIL.Emit(OpCodes.Box, typeof(Int32)); 
     setIL.Emit(OpCodes.Ldarg_0); 
     setIL.Emit(OpCodes.Ldnull); 
     setIL.Emit(OpCodes.Ldnull); 

     Type[] types = new Type[3]; 
     types[0] = typeof(object); 
     types[1] = typeof(IServiceProvider); 
     types[2] = typeof(IDictionary<object, object>); 

     setIL.Emit(OpCodes.Newobj, typeof(System.ComponentModel.DataAnnotations.ValidationContext).GetConstructor(types)); 
     setIL.Emit(OpCodes.Stloc_0); 
     setIL.Emit(OpCodes.Ldloc_0); 
     setIL.Emit(OpCodes.Ldstr, "TestProperty"); 
     setIL.Emit(OpCodes.Callvirt, typeof(System.ComponentModel.DataAnnotations.ValidationContext).GetMethod("set_MemberName")); 
     setIL.Emit(OpCodes.Ldloc_0); 
     setIL.Emit(OpCodes.Call, typeof(System.ComponentModel.DataAnnotations.Validator).GetMethod("ValidateProperty")); 

     setIL.Emit(OpCodes.Ldarg_0); 
     setIL.Emit(OpCodes.Ldarg_1); 
     setIL.Emit(OpCodes.Stfld, fieldBuilder); 
     setIL.Emit(OpCodes.Ret); 

這只是我的代碼的一部分,我設法讓它在沒有Validator.Valida的情況下工作teProperty與最後4行代碼。在我想要添加驗證功能的16個其他行中,現在會導致'操作可能會破壞運行時'的異常。

+0

你看着面向方面編程? http://en.wikipedia.org/wiki/Aspect-oriented_programming – MattDavey

回答

1

想通了自己:)

這是你需要發出Validator.Validate在屬性setter代碼:

 MethodBuilder setPropMthdBldr = 
      tb.DefineMethod("set_" + "TestProperty", 
       MethodAttributes.Public | 
       MethodAttributes.SpecialName | 
       MethodAttributes.HideBySig, 
       null, new Type[] { propertyType }); 


     ConstructorInfo ctor1 = typeof(ValidationContext).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, 
                     null, 
                     new Type[]{ 
                       typeof(Object), 
                       typeof(IServiceProvider), 
                       typeof(IDictionary<object, object>)}, 
                     null); 

     MethodInfo method2 = typeof(ValidationContext).GetMethod("set_MemberName", 
                   BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, 
                   null, 
                   new Type[]{typeof(String)}, 
                   null); 

     MethodInfo method3 = typeof(Validator).GetMethod("ValidateProperty", 
                 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, 
                 null, 
                 new Type[]{ 
                   typeof(Object), 
                   typeof(ValidationContext)}, 
                 null); 

     ILGenerator setIL = setPropMthdBldr.GetILGenerator(); 

     setIL.DeclareLocal(typeof(System.ComponentModel.DataAnnotations.ValidationContext)); 

     setIL.Emit(OpCodes.Nop); 
     setIL.Emit(OpCodes.Ldarg_1); 
     setIL.Emit(OpCodes.Box, typeof(Int32)); //in this case it's int32, should be your property type 
     setIL.Emit(OpCodes.Ldarg_0); 
     setIL.Emit(OpCodes.Ldnull); 
     setIL.Emit(OpCodes.Ldnull); 
     setIL.Emit(OpCodes.Newobj, ctor1); 
     setIL.Emit(OpCodes.Stloc_0); 
     setIL.Emit(OpCodes.Ldloc_0); 
     setIL.Emit(OpCodes.Ldstr, "TestProperty"); 
     setIL.Emit(OpCodes.Callvirt, method2); 
     setIL.Emit(OpCodes.Nop); 
     setIL.Emit(OpCodes.Ldloc_0); 
     setIL.Emit(OpCodes.Call, method3); 
     setIL.Emit(OpCodes.Nop); 
     setIL.Emit(OpCodes.Ldarg_0); 
     setIL.Emit(OpCodes.Ldarg_1); 
     setIL.Emit(OpCodes.Stfld, fieldBuilder); //the fieldbuilder you are using to define the private field 
     setIL.Emit(OpCodes.Ret); 
相關問題