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?
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
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);
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.
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.
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.