| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8d6a918 commit fc31de1
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -119,6 +119,15 @@ public void BaseClearIsCalled() | |||
| 119 | 119 | scope.Set("exn", null); | |
| 120 | 120 | Assert.AreEqual(1, msg.Refcount); | |
| 121 | 121 | } | |
| 122 | + | ||
| 123 | + // https://github.com/pythonnet/pythonnet/issues/1455 | ||
| 124 | + [Test] | ||
| 125 | + public void PropertyAccessorOverridden() | ||
| 126 | + { | ||
| 127 | + using var derived = new PropertyAccessorDerived().ToPython(); | ||
| 128 | + derived.SetAttr(nameof(PropertyAccessorDerived.VirtualProp), "hi".ToPython()); | ||
| 129 | + Assert.AreEqual("HI", derived.GetAttr(nameof(PropertyAccessorDerived.VirtualProp)).As<string>()); | ||
| 130 | + } | ||
| 122 | 131 | } | |
| 123 | 132 | ||
| 124 | 133 | class ExtraBaseTypeProvider : IPythonBaseTypeProvider | |
@@ -192,6 +201,18 @@ public int XProp | |||
| 192 | 201 | } | |
| 193 | 202 | } | |
| 194 | 203 | ||
| 204 | + public class PropertyAccessorBase | ||
| 205 | + { | ||
| 206 | + public virtual string VirtualProp { get; set; } | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + public class PropertyAccessorIntermediate: PropertyAccessorBase { } | ||
| 210 | + | ||
| 211 | + public class PropertyAccessorDerived: PropertyAccessorIntermediate | ||
| 212 | + { | ||
| 213 | + public override string VirtualProp { set => base.VirtualProp = value.ToUpperInvariant(); } | ||
| 214 | + } | ||
| 215 | + | ||
| 195 | 216 | public class ContainerClass | |
| 196 | 217 | { | |
| 197 | 218 | public void BaseMethod() { } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,56 @@ | |||
| 1 | + namespace Python.Runtime; | ||
| 2 | + | ||
| 3 | + using System; | ||
| 4 | + using System.Reflection; | ||
| 5 | + | ||
| 6 | + static class ReflectionUtil | ||
| 7 | + { | ||
| 8 | + public static MethodInfo? GetBaseGetMethod(this PropertyInfo property, bool nonPublic) | ||
| 9 | + { | ||
| 10 | + if (property is null) throw new ArgumentNullException(nameof(property)); | ||
| 11 | + | ||
| 12 | + Type baseType = property.DeclaringType.BaseType; | ||
| 13 | + BindingFlags bindingFlags = property.GetBindingFlags(); | ||
| 14 | + | ||
| 15 | + while (baseType is not null) | ||
| 16 | + { | ||
| 17 | + var baseProperty = baseType.GetProperty(property.Name, bindingFlags | BindingFlags.DeclaredOnly); | ||
| 18 | + var accessor = baseProperty?.GetGetMethod(nonPublic); | ||
| 19 | + if (accessor is not null) | ||
| 20 | + return accessor; | ||
| 21 | + | ||
| 22 | + baseType = baseType.BaseType; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + return null; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public static MethodInfo? GetBaseSetMethod(this PropertyInfo property, bool nonPublic) | ||
| 29 | + { | ||
| 30 | + if (property is null) throw new ArgumentNullException(nameof(property)); | ||
| 31 | + | ||
| 32 | + Type baseType = property.DeclaringType.BaseType; | ||
| 33 | + BindingFlags bindingFlags = property.GetBindingFlags(); | ||
| 34 | + | ||
| 35 | + while (baseType is not null) | ||
| 36 | + { | ||
| 37 | + var baseProperty = baseType.GetProperty(property.Name, bindingFlags | BindingFlags.DeclaredOnly); | ||
| 38 | + var accessor = baseProperty?.GetSetMethod(nonPublic); | ||
| 39 | + if (accessor is not null) | ||
| 40 | + return accessor; | ||
| 41 | + | ||
| 42 | + baseType = baseType.BaseType; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + return null; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public static BindingFlags GetBindingFlags(this PropertyInfo property) | ||
| 49 | + { | ||
| 50 | + var accessor = property.GetMethod ?? property.SetMethod; | ||
| 51 | + BindingFlags flags = default; | ||
| 52 | + flags |= accessor.IsStatic ? BindingFlags.Static : BindingFlags.Instance; | ||
| 53 | + flags |= accessor.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic; | ||
| 54 | + return flags; | ||
| 55 | + } | ||
| 56 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,6 @@ | |||
| 1 | 1 | using System; | |
| 2 | 2 | using System.Reflection; | |
| 3 | + using System.Runtime.Serialization; | ||
| 3 | 4 | ||
| 4 | 5 | namespace Python.Runtime | |
| 5 | 6 | { | |
@@ -8,17 +9,25 @@ namespace Python.Runtime | |||
| 8 | 9 | /// Implements a Python descriptor type that manages CLR properties. | |
| 9 | 10 | /// </summary> | |
| 10 | 11 | [Serializable] | |
| 11 | - internal class PropertyObject : ExtensionType | ||
| 12 | + internal class PropertyObject : ExtensionType, IDeserializationCallback | ||
| 12 | 13 | { | |
| 13 | 14 | internal MaybeMemberInfo<PropertyInfo> info; | |
| 14 | - private MaybeMethodInfo getter; | ||
| 15 | - private MaybeMethodInfo setter; | ||
| 15 | + [NonSerialized] | ||
| 16 | + private MethodInfo? getter; | ||
| 17 | + [NonSerialized] | ||
| 18 | + private MethodInfo? setter; | ||
| 16 | 19 | ||
| 17 | 20 | public PropertyObject(PropertyInfo md) | |
| 18 | 21 | { | |
| 19 | - getter = md.GetGetMethod(true); | ||
| 20 | - setter = md.GetSetMethod(true); | ||
| 21 | 22 | info = new MaybeMemberInfo<PropertyInfo>(md); | |
| 23 | + CacheAccessors(); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + void CacheAccessors() | ||
| 27 | + { | ||
| 28 | + PropertyInfo md = info.Value; | ||
| 29 | + getter = md.GetGetMethod(true) ?? md.GetBaseGetMethod(true); | ||
| 30 | + setter = md.GetSetMethod(true) ?? md.GetBaseSetMethod(true); | ||
| 22 | 31 | } | |
| 23 | 32 | ||
| 24 | 33 | ||
@@ -35,7 +44,7 @@ public static NewReference tp_descr_get(BorrowedReference ds, BorrowedReference | |||
| 35 | 44 | return Exceptions.RaiseTypeError(self.info.DeletedMessage); | |
| 36 | 45 | } | |
| 37 | 46 | var info = self.info.Value; | |
| 38 | - MethodInfo getter = self.getter.UnsafeValue; | ||
| 47 | + MethodInfo? getter = self.getter; | ||
| 39 | 48 | object result; | |
| 40 | 49 | ||
| 41 | 50 | ||
@@ -70,7 +79,7 @@ public static NewReference tp_descr_get(BorrowedReference ds, BorrowedReference | |||
| 70 | 79 | ||
| 71 | 80 | try | |
| 72 | 81 | { | |
| 73 | - result = info.GetValue(co.inst, null); | ||
| 82 | + result = getter.Invoke(co.inst, Array.Empty<object>()); | ||
| 74 | 83 | return Converter.ToPython(result, info.PropertyType); | |
| 75 | 84 | } | |
| 76 | 85 | catch (Exception e) | |
@@ -100,7 +109,7 @@ public static int tp_descr_set(BorrowedReference ds, BorrowedReference ob, Borro | |||
| 100 | 109 | } | |
| 101 | 110 | var info = self.info.Value; | |
| 102 | 111 | ||
| 103 | - MethodInfo setter = self.setter.UnsafeValue; | ||
| 112 | + MethodInfo? setter = self.setter; | ||
| 104 | 113 | ||
| 105 | 114 | if (val == null) | |
| 106 | 115 | { | |
@@ -141,7 +150,7 @@ public static int tp_descr_set(BorrowedReference ds, BorrowedReference ob, Borro | |||
| 141 | 150 | Exceptions.RaiseTypeError("invalid target"); | |
| 142 | 151 | return -1; | |
| 143 | 152 | } | |
| 144 | - info.SetValue(co.inst, newval, null); | ||
| 153 | + setter.Invoke(co.inst, new object?[] { newval }); | ||
| 145 | 154 | } | |
| 146 | 155 | else | |
| 147 | 156 | { | |
@@ -169,5 +178,13 @@ public static NewReference tp_repr(BorrowedReference ob) | |||
| 169 | 178 | var self = (PropertyObject)GetManagedObject(ob)!; | |
| 170 | 179 | return Runtime.PyString_FromString($"<property '{self.info}'>"); | |
| 171 | 180 | } | |
| 181 | + | ||
| 182 | + void IDeserializationCallback.OnDeserialization(object sender) | ||
| 183 | + { | ||
| 184 | + if (info.Valid) | ||
| 185 | + { | ||
| 186 | + CacheAccessors(); | ||
| 187 | + } | ||
| 188 | + } | ||
| 172 | 189 | } | |
| 173 | 190 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments