2011-12-07 23 views
1

Silverlightクライアントでは、実行時にクラスを生成してDataGridにバインドします。私はthisブログの投稿に基づいてメソッドを使用しています。 これで、プロパティセットでValidatePropertyを呼び出すことで、DataGridのセル検証を使用したいと考えています。しかし、プロパティは実行時に生成されるので、私はこれをReflection.Emitで行う必要があります。プロパティ設定ツールで検証コードを発行するには

これは私がILで生成するC#のである:

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 
} 

そしてこれはリフレクションでそれを書き込もうと私です。 Emitter:

 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行では、検証機能を追加したいが、今は 'Operationがランタイム'例外を不安定にする可能性がある。

+0

あなたはアスペクト指向プログラミングに見たことがありますか? http://en.wikipedia.org/wiki/Aspect-oriented_programming – MattDavey

答えて

1

は自分自身をそれを考え出した:)

をこれはあなたのプロパティのセッターでValidator.Validateを放出する必要があるコードです:

 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); 
関連する問題