X Tutup
using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.Serialization; using static Python.Runtime.PythonException; namespace Python.Runtime; [Serializable] internal sealed class ReflectedClrType : PyType { private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { } internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { } internal ReflectedClrType(BorrowedReference original) : base(original) { } ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { } internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!; /// /// Get the Python type that reflects the given CLR type. /// /// /// Returned might be partially initialized. /// public static ReflectedClrType GetOrCreate(Type type) { if (ClassManager.cache.TryGetValue(type, out var pyType)) { return pyType; } try { // Ensure, that matching Python type exists first. // It is required for self-referential classes // (e.g. with members, that refer to the same class) pyType = AllocateClass(type); ClassManager.cache.Add(type, pyType); var impl = ClassManager.CreateClass(type); TypeManager.InitializeClassCore(type, pyType, impl); ClassManager.InitClassBase(type, impl, pyType); // Now we force initialize the Python type object to reflect the given // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. TypeManager.InitializeClass(pyType, impl, type); } catch (Exception e) { throw new InternalPythonnetException($"Failed to create Python type for {type.FullName}", e); } return pyType; } internal void Restore(Dictionary context) { var cb = (ClassBase)context["impl"]!; Debug.Assert(cb is not null); cb!.Load(this, context); Restore(cb); } internal void Restore(ClassBase cb) { ClassManager.InitClassBase(cb.type.Value, cb, this); TypeManager.InitializeClass(this, cb, cb.type.Value); } internal static NewReference CreateSubclass(ClassBase baseClass, IList interfaces, string name, string? assembly, string? ns, BorrowedReference dict) { try { Type subType = ClassDerivedObject.CreateDerivedType(name, baseClass.type.Value, interfaces, dict, ns, assembly); var py_type = GetOrCreate(subType); // by default the class dict will have all the C# methods in it, but as this is a // derived class we want the python overrides in there instead if they exist. var cls_dict = Util.ReadRef(py_type, TypeOffset.tp_dict); ThrowIfIsNotZero(Runtime.PyDict_Update(cls_dict, dict)); // Update the __classcell__ if it exists BorrowedReference cell = Runtime.PyDict_GetItemString(cls_dict, "__classcell__"); if (!cell.IsNull) { ThrowIfIsNotZero(Runtime.PyCell_Set(cell, py_type)); ThrowIfIsNotZero(Runtime.PyDict_DelItemString(cls_dict, "__classcell__")); } return new NewReference(py_type); } catch (Exception e) { return Exceptions.RaiseTypeError(e.Message); } } static ReflectedClrType AllocateClass(Type clrType) { string name = TypeManager.GetPythonTypeName(clrType); var type = TypeManager.AllocateTypeObject(name, Runtime.PyCLRMetaType); type.Flags = TypeFlags.Default | TypeFlags.HasClrInstance | TypeFlags.HeapType | TypeFlags.BaseType | TypeFlags.HaveGC; return new ReflectedClrType(type.Steal()); } public override bool Equals(PyObject? other) => rawPtr == other?.DangerousGetAddressOrNull(); public override int GetHashCode() => rawPtr.GetHashCode(); }
X Tutup