From 9b6d67c1f4f59dd699e90357ed10ed35e6f118fa Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Sun, 12 Jan 2020 02:13:23 -0600 Subject: [PATCH] Fixed property accessor for value types --- IPA.Loader/Utilities/Accessor.cs | 50 +++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/IPA.Loader/Utilities/Accessor.cs b/IPA.Loader/Utilities/Accessor.cs index 67f7270a..6e79bf36 100644 --- a/IPA.Loader/Utilities/Accessor.cs +++ b/IPA.Loader/Utilities/Accessor.cs @@ -134,13 +134,13 @@ namespace IPA.Utilities /// /// the object it is a member of /// the value of the property - public delegate U Getter(T obj); + public delegate U Getter(ref T obj); /// /// A setter for a property. /// /// the object it is a member of /// the new property value - public delegate void Setter(T obj, U val); + public delegate void Setter(ref T obj, U val); private static readonly Dictionary props = new Dictionary(); @@ -154,10 +154,40 @@ namespace IPA.Utilities var setM = prop.GetSetMethod(true); Getter getter = null; Setter setter = null; - if (getM != null) - getter = (Getter)Delegate.CreateDelegate(typeof(Getter), getM); - if (setM != null) - setter = (Setter)Delegate.CreateDelegate(typeof(Setter), setM); + + if (typeof(T).IsValueType) + { + if (getM != null) + getter = (Getter)Delegate.CreateDelegate(typeof(Getter), getM); + if (setM != null) + setter = (Setter)Delegate.CreateDelegate(typeof(Setter), setM); + } + else + { + if (getM != null) + { + var dyn = new DynamicMethod($"<>_get__{propName}", typeof(U), new[] { typeof(T).MakeByRefType() }, typeof(PropertyAccessor), true); + var il = dyn.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldind_Ref); + il.Emit(OpCodes.Tailcall); + il.Emit(getM.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getM); + il.Emit(OpCodes.Ret); + getter = (Getter)dyn.CreateDelegate(typeof(Getter)); + } + if (setM != null) + { + var dyn = new DynamicMethod($"<>_set__{propName}", typeof(void), new[] { typeof(T).MakeByRefType(), typeof(U) }, typeof(PropertyAccessor), true); + var il = dyn.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldind_Ref); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Tailcall); + il.Emit(setM.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, setM); + il.Emit(OpCodes.Ret); + setter = (Setter)dyn.CreateDelegate(typeof(Setter)); + } + } return (getter, setter); } @@ -197,7 +227,7 @@ namespace IPA.Utilities /// when the property does not exist /// /// - public static U Get(ref T obj, string name) => GetGetter(name)(obj); + public static U Get(ref T obj, string name) => GetGetter(name)(ref obj); /// /// Gets the value of the property identified by on . /// @@ -207,7 +237,7 @@ namespace IPA.Utilities /// when the property does not exist /// /// - public static U Get(T obj, string name) => GetGetter(name)(obj); + public static U Get(T obj, string name) => GetGetter(name)(ref obj); /// /// Sets the value of the property identified by on . /// @@ -220,7 +250,7 @@ namespace IPA.Utilities /// when the property does not exist /// /// - public static void Set(ref T obj, string name, U val) => GetSetter(name)(obj, val); + public static void Set(ref T obj, string name, U val) => GetSetter(name)(ref obj, val); /// /// Sets the value of the property identified by on . /// @@ -233,6 +263,6 @@ namespace IPA.Utilities /// when the property does not exist /// /// - public static void Set(T obj, string name, U val) => GetSetter(name)(obj, val); + public static void Set(T obj, string name, U val) => GetSetter(name)(ref obj, val); } }