18 using System.Collections.Generic;
27 private PyObject _instance;
28 private object _underlyingClrObject;
29 private Dictionary<string, PyObject> _pythonMethods;
30 private Dictionary<string, string> _pythonPropertyNames;
32 private readonly
bool _validateInterface;
45 _pythonMethods =
new();
46 _pythonPropertyNames =
new();
47 _validateInterface = validateInterface;
56 : this(validateInterface)
67 if (_instance !=
null)
69 _pythonMethods.Clear();
70 _pythonPropertyNames.Clear();
73 _instance = _validateInterface ? instance.ValidateImplementationOf<TInterface>() : instance;
74 _instance.TryConvert(out _underlyingClrObject);
83 using var _ = Py.GIL();
84 return GetProperty(propertyName).GetAndDispose<T>();
93 using var _ = Py.GIL();
94 return _instance.GetAttr(GetPropertyName(propertyName));
104 using var _ = Py.GIL();
105 _instance.SetAttr(GetPropertyName(propertyName), value.ToPython());
114 using var _ = Py.GIL();
115 return _instance.GetAttr(GetPropertyName(name,
true));
125 using var _ = Py.GIL();
126 return _instance.HasAttr(name) || _instance.HasAttr(name.ToSnakeCase());
136 if (!_pythonMethods.TryGetValue(methodName, out var method))
138 method = _instance.GetMethod(methodName);
139 _pythonMethods = AddToDictionary(_pythonMethods, methodName, method);
153 using var _ = Py.GIL();
155 return method.Invoke<T>(args);
165 using var _ = Py.GIL();
167 return method.Invoke(args);
170 private string GetPropertyName(
string propertyName,
bool isEvent =
false)
172 if (!_pythonPropertyNames.TryGetValue(propertyName, out var pythonPropertyName))
174 var snakeCasedPropertyName = propertyName.ToSnakeCase();
178 if (!isEvent && _underlyingClrObject !=
null)
180 var underlyingClrObjectType = _underlyingClrObject.GetType();
181 var
property = underlyingClrObjectType.GetProperty(propertyName);
182 if (property !=
null)
184 var clrPropertyValue =
property.GetValue(_underlyingClrObject);
185 var pyObjectSnakeCasePropertyValue = _instance.GetAttr(snakeCasedPropertyName);
187 if (!pyObjectSnakeCasePropertyValue.TryConvert(out
object pyObjectSnakeCasePropertyClrValue,
true) ||
188 !ReferenceEquals(clrPropertyValue, pyObjectSnakeCasePropertyClrValue))
190 pythonPropertyName = snakeCasedPropertyName;
194 pythonPropertyName = propertyName;
199 if (pythonPropertyName ==
null)
201 pythonPropertyName = snakeCasedPropertyName;
202 if (!_instance.HasAttr(pythonPropertyName))
204 pythonPropertyName = propertyName;
208 _pythonPropertyNames = AddToDictionary(_pythonPropertyNames, propertyName, pythonPropertyName);
211 return pythonPropertyName;
219 private static Dictionary<string, T> AddToDictionary<T>(Dictionary<string, T> dictionary,
string key, T value)
221 return new Dictionary<string, T>(dictionary)
235 return other is not
null && (ReferenceEquals(
this, other) ||
Equals(other._instance));
255 using var _ = Py.GIL();
256 return PythonReferenceComparer.Instance.GetHashCode(_instance);
262 private bool Equals(PyObject other)
264 if (other is
null)
return false;
265 if (ReferenceEquals(_instance, other))
return true;
267 using var _ = Py.GIL();
269 return PythonReferenceComparer.Instance.Equals(_instance, other);