Laden...

[erledigt] Per Reflection.Emit einen Event mit explizitem add und remove generieren

Erstellt von Robin0 vor 10 Jahren Letzter Beitrag vor 9 Jahren 1.065 Views
R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren
[erledigt] Per Reflection.Emit einen Event mit explizitem add und remove generieren

Hallo,

Ich versuche gerade INotifyPropertyChanged in eine per Reflection.Emit erstelle klasse einzubinden.

Ich hänge gerade fest, weil ich es nicht hinbekommen einen add und einen remove handler zu erstellen.


private PropertyChangedEventHandler PropertyChange;

/*Eig nur der untere teil*/
public event PropertyChangedEventHandler PropertyChanged
        {
            add { PropertyChange += value; }
            remove { PropertyChange -= value; }
        }

Weiß vielleicht jemand weiter, oder kennt ein buch über Reflection.emit?

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Robin0,

willst du diese Konstruktion genau so, oder ist das nur ein Beispiel, das du im konkreten Fall noch abwandeln willst. Denn so wie die Konstruktion dasteht, macht sie aus meiner Sicht keinen Sinn und könnte ohne weiteres komplett durch folgende Zeile ersetzt werden:

public event PropertyChangedEventHandler PropertyChanged;

herbivore

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Ich bekomm ne fehlermeldung dass:

Fehlermeldung:
{"Die Methode "add_PropertyChanged" im Typ "Dynamic.DynamicType" der Assembly "Dynamic.DynamicAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" hat keine Implementierung.":"Dynamic.DynamicType"}

Der fehler tritt bei "_tb.CreateType();" auf

Mein reflection code dazu ist:


/*_tb is mein TypeBuilder*/

_tb.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));

/*Jedes Feld bekommt bei mir ein eigenschaft, den setter baue ich so auf*/
MethodBuilder setPropMthdBldr =
                _tb.DefineMethod("set_" + _propertyName,
                  MethodAttributes.Public |
                  MethodAttributes.SpecialName |
                  MethodAttributes.HideBySig,
                  null, new[] { _propertyType });

            ILGenerator setIl = setPropMthdBldr.GetILGenerator();
            System.Reflection.Emit.Label modifyProperty = setIl.DefineLabel();
            System.Reflection.Emit.Label exitSet = setIl.DefineLabel();

            setIl.MarkLabel(modifyProperty);
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);

            /*INotifyPropertyChanged aufruf*/
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldstr, _propertyName);
            setIl.EmitCalli(OpCodes.Calli, System.Runtime.InteropServices.CallingConvention.ThisCall, typeof(void), new[] { typeof(Object), typeof(PropertyChangedEventArgs) });
             /**/

            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(exitSet);
            setIl.Emit(OpCodes.Ret);

D
96 Beiträge seit 2012
vor 10 Jahren

In deinem Code fügst du auch keine Add oder Remove Methode zu dem Event hinzu.

EventBuilder ev = _tb.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler)); 

MethodBuilder addMethod = ...;
// Define Method ...
//...
ev.SetAddOnMethod(addMethod);

Daher ist auch keine Implementierung vorhanden.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Habs denke ich:


            FieldBuilder eventField = tb.DefineField("m_PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Public);

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

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

            MethodImplAttributes eventMethodFlags = MethodImplAttributes.Managed;
            mbEV.SetImplementationFlags(eventMethodFlags);
            var removeIl = mbEV.GetILGenerator();
            removeIl.Emit(OpCodes.Ldarg_0);
            removeIl.Emit(OpCodes.Ldarg_0);
            removeIl.Emit(OpCodes.Ldfld, eventField);
            removeIl.Emit(OpCodes.Ldarg_1);
            removeIl.EmitCall(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) }), null);
            removeIl.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
            removeIl.Emit(OpCodes.Stfld, eventField);
            removeIl.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.HideBySig | MethodAttributes.Virtual
                , null, new[] { typeof(PropertyChangedEventHandler) });

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

Das einzige was ich jetz noch machen muss is meine "RaisePropertyChanged" im setter der variable aufzurufen

RaisePropertyChanged:


MethodBuilder mbRaisePropertyChanged = tb.DefineMethod("RaisePropertyChanged", MethodAttributes.Virtual, null, new Type[] { typeof(string) });

            var RaiseIl = mbRaisePropertyChanged.GetILGenerator();
            System.Reflection.Emit.Label RaiseIlExitLabel = RaiseIl.DefineLabel();
            RaiseIl.Emit(OpCodes.Ldarg_0);
            RaiseIl.Emit(OpCodes.Ldfld, eventField);//if
            RaiseIl.Emit(OpCodes.Ldnull);
            RaiseIl.Emit(OpCodes.Ceq);
            RaiseIl.Emit(OpCodes.Brtrue, RaiseIlExitLabel);//endif
            RaiseIl.Emit(OpCodes.Pop);
            RaiseIl.Emit(OpCodes.Ldarg_0);
            RaiseIl.Emit(OpCodes.Ldfld, eventField);
            RaiseIl.Emit(OpCodes.Ldarg_0);
            RaiseIl.Emit(OpCodes.Ldarg_1);
            RaiseIl.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) }));
            RaiseIl.EmitCall(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"), null);
            RaiseIl.Emit(OpCodes.Nop);
            RaiseIl.Emit(OpCodes.Nop);
            RaiseIl.MarkLabel(RaiseIlExitLabel);
            RaiseIl.Emit(OpCodes.Ret);

Ich hab das erstellen der eigenschaften in eine Methode ausgelagert, und kenne "mbRaisePropertyChanged" da nicht, wie rufe ich die dann auf?? der typ is ja nochnich erstellt und ich kann die Methode dann nichg mit Type.GetMethod() suchen, da der Typ nochnich existiert.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 9 Jahren

Soo nach langem sochen habe ich eine Losung gefunden:

Hier ist alles ziemlich genau beschrieben 😃.
Dynamically generating types to implement INotifyPropertyChanged

Die WrpapMethod Funktioniert zwar nicht, aber das ist nebensache man kann den aufruf ja direkt in den setter einbauen.