首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用INotifyPropertyChanged实现Reflection.Emit

用INotifyPropertyChanged实现Reflection.Emit
EN

Stack Overflow用户
提问于 2010-09-03 20:48:16
回答 1查看 3K关注 0票数 5

使用C#/.Net 4.0,我将数据存储在一个BindingList中,其中dataRow是通过Reflection.Emit在运行时定义的。(传入数据的结构各不相同,由外部源定义。)在第一次尝试反射和IL之后,我已经能够创建我的dataRow,用值填充它,填充BindingList并在网格中显示结果。当对数据进行更改时,我现在正在尝试实现INotifyPropertyChanged接口和PropertyChangedEventHandler。使用作为指导,我获得了运行的代码,但似乎没有显示RaisePropertyChanged事件正在触发,或者它只是什么也不做。当我通过ildasm.exe将我的动态版本与普通/静态版本进行比较时,我看到了remove_PropertyChanged和add_PropertyChanged方法的主要区别。有人能提供一些通过反射实现INotifyPropertyChanged接口的技巧或示例吗?

经过进一步的检查,事件字段似乎必须为null,因此不会调用PropertyChangedEventHandler。我在RaiseProprtyChanged方法构建器中添加了一些消息框,发现等效的if (PropertyChanged != null)返回0/false,所以什么都不会发生。如果将OpCodes.Brtrue更改为OpCodes.Brfalse,则会收到“对象引用未设置为对象实例”的消息。感觉好像我错过了一些简单的东西,但我找不到。

代码语言:javascript
复制
            //implement IINotifyPropertyChanged interface
        tb.AddInterfaceImplementation(typeof(INotifyPropertyChanged));

        //property changed event handler
        FieldBuilder eventField = tb.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);

        EventBuilder eb = tb.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));

        MethodBuilder mbEV = tb.DefineMethod("remove_PropertyChanged", MethodAttributes.Public |
            MethodAttributes.SpecialName | MethodAttributes.NewSlot |
            MethodAttributes.HideBySig | MethodAttributes.Virtual |
            MethodAttributes.Final, null, new[] { typeof(PropertyChangedEventHandler) });

        MethodImplAttributes eventMethodFlags = MethodImplAttributes.Managed; //| MethodImplAttributes.Synchronized;
        mbEV.SetImplementationFlags(eventMethodFlags);
        il = mbEV.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldarg_1);
        il.EmitCall(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) }), null);
        il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
        il.Emit(OpCodes.Stfld, eventField);
        il.Emit(OpCodes.Ret);
        MethodInfo miRemoveEvent = typeof(INotifyPropertyChanged).GetMethod("remove_PropertyChanged");
        tb.DefineMethodOverride(mbEV, miRemoveEvent);
        eb.SetRemoveOnMethod(mbEV);

        mbEV = tb.DefineMethod("add_PropertyChanged", MethodAttributes.Public |
            MethodAttributes.SpecialName | MethodAttributes.NewSlot |
            MethodAttributes.HideBySig | MethodAttributes.Virtual |
            MethodAttributes.Final, null, new[] { typeof(PropertyChangedEventHandler) });

        mbEV.SetImplementationFlags(eventMethodFlags);
        il = mbEV.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldarg_1);
        il.EmitCall(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) }), null);
        il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
        il.Emit(OpCodes.Stfld, eventField);
        il.Emit(OpCodes.Ret);
        MethodInfo miAddEvent = typeof(INotifyPropertyChanged).GetMethod("add_PropertyChanged");
        tb.DefineMethodOverride(mbEV, miAddEvent);
        eb.SetAddOnMethod(mbEV);

        MethodInfo msgboxMethodInfo = typeof(System.Windows.Forms.MessageBox).GetMethod("Show", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, new Type[] { typeof(String) }, null);

        MethodBuilder mbRaisePropertyChanged = tb.DefineMethod("RaisePropertyChanged", MethodAttributes.Virtual, null, new Type[] { typeof(string) });
        il = mbRaisePropertyChanged.GetILGenerator();
        System.Reflection.Emit.Label labelExit = il.DefineLabel();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldnull);
        il.Emit(OpCodes.Ceq); //this is returning false
        il.Emit(OpCodes.Brtrue, labelExit);
        il.Emit(OpCodes.Nop); //I never get here
        il.Emit(OpCodes.Ldstr, "After If");
        il.EmitCall(OpCodes.Call, msgboxMethodInfo, null);
        il.Emit(OpCodes.Pop);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldfld, eventField);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) }));
        il.EmitCall(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"), null);
        il.Emit(OpCodes.Nop);
        il.Emit(OpCodes.Nop);
        il.MarkLabel(labelExit);
        il.Emit(OpCodes.Ret);
EN

回答 1

Stack Overflow用户

发布于 2010-09-05 12:40:16

如果您试图修改程序集的IL,我将盗用以避免反射。您可能会遇到程序集锁定问题。

至于解决方案,请尝试这些链接。

定制编织

  • NotifyPropertyWeaver
  • http://justinangel.net/AutomagicallyImplementingINotifyPropertyChanged

使用后锐器

  • http://www.lesnikowski.com/blog/index.php/inotifypropertychanged-with-postsharp/
  • http://www.sharpcrafters.com/solutions/ui
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3639479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档