C# 如何在属性设置器中发出验证代码

C# 如何在属性设置器中发出验证代码,c#,silverlight,reflection.emit,C#,Silverlight,Reflection.emit,在我的Silverlight客户端上,我在运行时生成一个类,将其绑定到datagrid。我正在使用一种基于博客帖子的方法。 现在我想通过在属性设置器中调用ValidateProperty来使用datagrid cellvalidation。但是由于属性是在运行时生成的,因此我需要在Reflection.Emit中执行此操作 这是我想在IL中生成的C#: public int TestProperty { get { return testProperty; }

在我的Silverlight客户端上,我在运行时生成一个类,将其绑定到datagrid。我正在使用一种基于博客帖子的方法。 现在我想通过在属性设置器中调用ValidateProperty来使用datagrid cellvalidation。但是由于属性是在运行时生成的,因此我需要在Reflection.Emit中执行此操作

这是我想在IL中生成的C#:

    public int TestProperty
    {
        get { return testProperty; }
        set 
        {
            Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "TestProperty" });
            testProperty = value; 
        }
    }
以下是ILspy在IL中反编译此方法的方式:

.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
}
.property int32 TestProperty
{
.获取公共隐藏的特殊名称
实例int32 get_TestProperty()cil托管
{
//方法从RVA 0x224c开始
//代码大小12(0xc)
.maxstack 1
.init(
[0]int32
)
IL_0000:没有
IL_0001:ldarg.0
IL_0002:ldfld int32类SilverlightApplication2.testclass::testProperty
IL_0007:stloc.0
IL_0008:br.s IL_000a
IL_000a:ldloc.0
IL_000b:ret
}//方法testclass.get\u TestProperty的结尾
.设置公共隐藏显示特殊名称
实例void set_TestProperty(
int32值
)cil管理
{
//方法从RVA 0x2264开始
//代码大小43(0x2b)
.maxstack 5
.init(
[0]类[System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext
)
IL_0000:没有
IL_0001:ldarg.1
IL_0002:box int32
IL_0007:ldarg.0
IL_0008:ldnull
IL_0009:ldnull
IL_000a:newobj实例void[System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext::.ctor(对象,类[mscorlib]System.IServiceProvider,类[mscorlib]System.Collections.Generic.IDictionary`2)
IL_000f:stloc.0
IL_0010:ldloc.0
IL_0011:ldstr“TestProperty”
IL_0016:callvirt实例void[System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext::set_MemberName(字符串)
IL_001b:没有
IL_001c:ldloc.0
IL001D:调用void[System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.Validator::ValidateProperty(对象,类[System.ComponentModel.DataAnnotations]System.ComponentModel.DataAnnotations.ValidationContext)
伊卢0022:没有
IL_0023:ldarg.0
IL_0024:ldarg.1
IL_0025:stfld int32类SilverlightApplication2.testclass::testProperty
IL_002a:ret
}//方法testclass.set\u TestProperty的结尾
}
这是我试图在反射中写的。发射:

        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);
setIL.Emit(操作码Ldarg_1);
setIL.Emit(opcode.Box,typeof(Int32));
setIL.Emit(操作码.Ldarg_0);
setIL.Emit(操作码.Ldnull);
setIL.Emit(操作码.Ldnull);
类型[]类型=新类型[3];
类型[0]=typeof(对象);
类型[1]=类型(IServiceProvider);
类型[2]=typeof(IDictionary);
Emit(OpCodes.Newobj,typeof(System.ComponentModel.DataAnnotations.ValidationContext).GetConstructor(types));
setIL.Emit(操作码Stloc_0);
setIL.Emit(操作码Ldloc_0);
setIL.Emit(opcode.Ldstr,“TestProperty”);
Emit(OpCodes.Callvirt,typeof(System.ComponentModel.DataAnnotations.ValidationContext.GetMethod(“set_MemberName”));
setIL.Emit(操作码Ldloc_0);
Emit(opcode.Call,typeof(System.ComponentModel.DataAnnotations.Validator).GetMethod(“ValidateProperty”);
setIL.Emit(操作码.Ldarg_0);
setIL.Emit(操作码Ldarg_1);
setIL.Emit(操作码.Stfld,fieldBuilder);
setIL.Emit(操作码Ret);
这只是我代码的一部分,我在没有Validator.ValidateProperty的情况下成功地使用了最后4行代码。对于另外16行,我想添加验证功能,但现在这会导致“操作可能会破坏运行时的稳定性”异常。

我自己解决了:)

这是发出验证程序所需的代码。请在属性设置程序中验证:

        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);
MethodBuilder setPropMthdBldr=
tb.DefineMethod(“设置”+“测试属性”,
MethodAttributes.Public|
MethodAttributes.SpecialName|
MethodAttributes.hidebysing,
null,新类型[]{propertyType});
ConstructorInfo ctor1=typeof(ValidationContext).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
无效的
新类型[]{
类型(对象),
类型(IServiceProvider),
类型(IDictionary)},
无效);
MethodInfo method2=typeof(ValidationContext).GetMethod(“set_MemberName”,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
无效的
新类型[]{typeof(String)},
无效);
MethodInfo method3=typeof(Validator).GetMethod(“ValidateProperty”,
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
无效的
新类型[]{
类型(对象),
类型(I)