Implementing INotifyPropertyChanged with Reflection.Emit

Using C#/.Net 4.0, I'm storing data in a BindingList where dataRow is being defined at run time via Reflection.Emit. (The structure of the incoming data varies and is defined by an external source.) After struggling a bit with my first foray into the world of reflection and IL, I have been able to create my dataRow fill it with values, fill my BindingList and display the result in a grid. I now am trying to implement the INotifyPropertyChanged interface and the PropertyChangedEventHandler when changes are made to the data. Using this as a guide, I've got code that runs but it doesn't appear that the RaisePropertyChanged event is firing or it just isn't doing anything. When I compare my dynamic version with a normal/static version via ildasm.exe I see major differences in the remove_PropertyChanged and add_PropertyChanged methods. Может ли кто-нибудь предоставить некоторые советы или примеры реализации интерфейса INotifyPropertyChanged с помощью отражения.

После дальнейшего рассмотрения кажется, что поле события должно быть нулевым, поэтому PropertyChangedEventHandler не вызывается. Я добавил несколько окон сообщений в конструктор методов RaiseProprtyChanged и обнаружил, что эквивалент if (PropertyChanged! = Null) возвращает ноль / ложь, поэтому ничего не происходит. Если я изменяю OpCodes.Brtrue на OpCodes.Brfalse, я получаю сообщение «Ссылка на объект не установлена ​​на экземпляр объекта». Такое ощущение, что я упустил что-то простое, но я не могу его найти.

            //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);

5
задан leppie 20 July 2012 в 06:31
поделиться