Browse Source

Use base class `NotifyPropertyChanged` method if available

pull/58/head
Zingabopp 4 years ago
parent
commit
dfb22cde7e
1 changed files with 131 additions and 106 deletions
  1. +131
    -106
      IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs

+ 131
- 106
IPA.Loader/Config/Stores/GeneratedStoreImpl/MakeCreator.cs View File

@ -145,139 +145,164 @@ namespace IPA.Config.Stores
MethodBuilder notifyChanged = null; MethodBuilder notifyChanged = null;
if (isINotifyPropertyChanged || hasNotifyAttribute) if (isINotifyPropertyChanged || hasNotifyAttribute)
{ {
var INotifyPropertyChanged_t = typeof(INotifyPropertyChanged);
typeBuilder.AddInterfaceImplementation(INotifyPropertyChanged_t);
var INotifyPropertyChanged_PropertyChanged =
INotifyPropertyChanged_t.GetEvent(nameof(INotifyPropertyChanged.PropertyChanged));
var PropertyChangedEventHandler_t = typeof(PropertyChangedEventHandler);
var PropertyChangedEventHander_Invoke = PropertyChangedEventHandler_t.GetMethod(nameof(PropertyChangedEventHandler.Invoke));
var PropertyChangedEventArgs_t = typeof(PropertyChangedEventArgs);
var PropertyChangedEventArgs_ctor = PropertyChangedEventArgs_t.GetConstructor(new[] { typeof(string) });
var Delegate_t = typeof(Delegate);
var Delegate_Combine = Delegate_t.GetMethod(nameof(Delegate.Combine), BindingFlags.Static | BindingFlags.Public, null,
new[] { Delegate_t, Delegate_t }, Array.Empty<ParameterModifier>());
var Delegate_Remove = Delegate_t.GetMethod(nameof(Delegate.Remove), BindingFlags.Static | BindingFlags.Public, null,
new[] { Delegate_t, Delegate_t }, Array.Empty<ParameterModifier>());
var CompareExchange = typeof(Interlocked).GetMethods()
.Where(m => m.Name == nameof(Interlocked.CompareExchange))
.Where(m => m.ContainsGenericParameters)
.Where(m => m.GetParameters().Length == 3).First()
.MakeGenericMethod(PropertyChangedEventHandler_t);
var basePropChangedEvent = type.GetEvents()
.Where(e => e.GetAddMethod().GetBaseDefinition().DeclaringType == INotifyPropertyChanged_t)
.FirstOrDefault();
var basePropChangedAdd = basePropChangedEvent?.GetAddMethod();
var basePropChangedRemove = basePropChangedEvent?.GetRemoveMethod();
var PropertyChanged_backing = typeBuilder.DefineField("<event>PropertyChanged", PropertyChangedEventHandler_t, FieldAttributes.Private);
if (isINotifyPropertyChanged)
{
var ExistingRaisePropertyChanged = type.GetMethod("RaisePropertyChanged", (BindingFlags)int.MaxValue, null, new Type[] { typeof(string) }, Array.Empty<ParameterModifier>());
if (ExistingRaisePropertyChanged != null)
{
notifyChanged = typeBuilder.DefineMethod("<>NotifyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final, null, new[] { typeof(string) });
var add_PropertyChanged = typeBuilder.DefineMethod("<add>PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual,
null, new[] { PropertyChangedEventHandler_t });
typeBuilder.DefineMethodOverride(add_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetAddMethod());
if (basePropChangedAdd != null)
typeBuilder.DefineMethodOverride(add_PropertyChanged, basePropChangedAdd);
{
var il = notifyChanged.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, ExistingRaisePropertyChanged);
il.Emit(OpCodes.Ret);
}
}
else
{
Logger.log.Critical($"Type '{type.FullName}' implements INotifyPropertyChanged but does not have a 'RaisePropertyChanged(string)' method, automatic raising of PropertyChanged event is disabled.");
}
}
else
{ {
var il = add_PropertyChanged.GetILGenerator();
var INotifyPropertyChanged_t = typeof(INotifyPropertyChanged);
typeBuilder.AddInterfaceImplementation(INotifyPropertyChanged_t);
var INotifyPropertyChanged_PropertyChanged =
INotifyPropertyChanged_t.GetEvent(nameof(INotifyPropertyChanged.PropertyChanged));
var PropertyChangedEventHandler_t = typeof(PropertyChangedEventHandler);
var PropertyChangedEventHander_Invoke = PropertyChangedEventHandler_t.GetMethod(nameof(PropertyChangedEventHandler.Invoke));
var PropertyChangedEventArgs_t = typeof(PropertyChangedEventArgs);
var PropertyChangedEventArgs_ctor = PropertyChangedEventArgs_t.GetConstructor(new[] { typeof(string) });
var Delegate_t = typeof(Delegate);
var Delegate_Combine = Delegate_t.GetMethod(nameof(Delegate.Combine), BindingFlags.Static | BindingFlags.Public, null,
new[] { Delegate_t, Delegate_t }, Array.Empty<ParameterModifier>());
var Delegate_Remove = Delegate_t.GetMethod(nameof(Delegate.Remove), BindingFlags.Static | BindingFlags.Public, null,
new[] { Delegate_t, Delegate_t }, Array.Empty<ParameterModifier>());
var CompareExchange = typeof(Interlocked).GetMethods()
.Where(m => m.Name == nameof(Interlocked.CompareExchange))
.Where(m => m.ContainsGenericParameters)
.Where(m => m.GetParameters().Length == 3).First()
.MakeGenericMethod(PropertyChangedEventHandler_t);
var basePropChangedEvent = type.GetEvents()
.Where(e => e.GetAddMethod().GetBaseDefinition().DeclaringType == INotifyPropertyChanged_t)
.FirstOrDefault();
var basePropChangedAdd = basePropChangedEvent?.GetAddMethod();
var basePropChangedRemove = basePropChangedEvent?.GetRemoveMethod();
var PropertyChanged_backing = typeBuilder.DefineField("<event>PropertyChanged", PropertyChangedEventHandler_t, FieldAttributes.Private);
var add_PropertyChanged = typeBuilder.DefineMethod("<add>PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual,
null, new[] { PropertyChangedEventHandler_t });
typeBuilder.DefineMethodOverride(add_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetAddMethod());
if (basePropChangedAdd != null)
typeBuilder.DefineMethodOverride(add_PropertyChanged, basePropChangedAdd);
var loopLabel = il.DefineLabel();
var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t);
{
var il = add_PropertyChanged.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, PropertyChanged_backing);
var loopLabel = il.DefineLabel();
var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t);
il.MarkLabel(loopLabel);
il.Emit(OpCodes.Stloc, delTemp);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, PropertyChanged_backing);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, PropertyChanged_backing);
il.MarkLabel(loopLabel);
il.Emit(OpCodes.Stloc, delTemp);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, Delegate_Combine);
il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, PropertyChanged_backing);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Call, CompareExchange);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, Delegate_Combine);
il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Bne_Un_S, loopLabel);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Call, CompareExchange);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
}
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Bne_Un_S, loopLabel);
var remove_PropertyChanged = typeBuilder.DefineMethod("<remove>PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual,
null, new[] { PropertyChangedEventHandler_t });
typeBuilder.DefineMethodOverride(remove_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetRemoveMethod());
if (basePropChangedRemove != null)
typeBuilder.DefineMethodOverride(remove_PropertyChanged, basePropChangedRemove);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
}
{
var il = remove_PropertyChanged.GetILGenerator();
var remove_PropertyChanged = typeBuilder.DefineMethod("<remove>PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final | MethodAttributes.Virtual,
null, new[] { PropertyChangedEventHandler_t });
typeBuilder.DefineMethodOverride(remove_PropertyChanged, INotifyPropertyChanged_PropertyChanged.GetRemoveMethod());
if (basePropChangedRemove != null)
typeBuilder.DefineMethodOverride(remove_PropertyChanged, basePropChangedRemove);
var loopLabel = il.DefineLabel();
var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t);
{
var il = remove_PropertyChanged.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, PropertyChanged_backing);
var loopLabel = il.DefineLabel();
var delTemp = il.DeclareLocal(PropertyChangedEventHandler_t);
il.MarkLabel(loopLabel);
il.Emit(OpCodes.Stloc, delTemp);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, PropertyChanged_backing);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, PropertyChanged_backing);
il.MarkLabel(loopLabel);
il.Emit(OpCodes.Stloc, delTemp);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, Delegate_Remove);
il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, PropertyChanged_backing);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Call, CompareExchange);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, Delegate_Remove);
il.Emit(OpCodes.Castclass, PropertyChangedEventHandler_t);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Bne_Un_S, loopLabel);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Call, CompareExchange);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
}
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldloc, delTemp);
il.Emit(OpCodes.Bne_Un_S, loopLabel);
var PropertyChanged_event = typeBuilder.DefineEvent(nameof(INotifyPropertyChanged.PropertyChanged), EventAttributes.None, PropertyChangedEventHandler_t);
PropertyChanged_event.SetAddOnMethod(add_PropertyChanged);
PropertyChanged_event.SetRemoveOnMethod(remove_PropertyChanged);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
}
notifyChanged = typeBuilder.DefineMethod("<>NotifyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final, null, new[] { typeof(string) });
var PropertyChanged_event = typeBuilder.DefineEvent(nameof(INotifyPropertyChanged.PropertyChanged), EventAttributes.None, PropertyChangedEventHandler_t);
PropertyChanged_event.SetAddOnMethod(add_PropertyChanged);
PropertyChanged_event.SetRemoveOnMethod(remove_PropertyChanged);
{
var il = notifyChanged.GetILGenerator();
notifyChanged = typeBuilder.DefineMethod("<>NotifyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Final, null, new[] { typeof(string) });
var invokeNonNull = il.DefineLabel();
{
var il = notifyChanged.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, PropertyChanged_backing);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Brtrue, invokeNonNull);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
var invokeNonNull = il.DefineLabel();
il.MarkLabel(invokeNonNull);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Newobj, PropertyChangedEventArgs_ctor);
il.Emit(OpCodes.Call, PropertyChangedEventHander_Invoke);
il.Emit(OpCodes.Ret);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, PropertyChanged_backing);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Brtrue, invokeNonNull);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);
il.MarkLabel(invokeNonNull);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Newobj, PropertyChangedEventArgs_ctor);
il.Emit(OpCodes.Call, PropertyChangedEventHander_Invoke);
il.Emit(OpCodes.Ret);
}
} }
} }
#endregion #endregion


Loading…
Cancel
Save