/// <summary> /// Return value: Borrowed reference. /// Get the handle of a Python type that reflects the given CLR type. /// The given ManagedType instance is a managed object that implements /// the appropriate semantics in Python for the reflected managed type. /// </summary> internal static IntPtr GetTypeHandle(ClassBase obj, Type type) { IntPtr handle; cache.TryGetValue(type, out handle); if (handle != IntPtr.Zero) { return(handle); } handle = CreateType(obj, type); cache[type] = handle; _slotsImpls.Add(type, obj.GetType()); return(handle); }
internal static IntPtr CreateType(ClassBase impl, Type clrType) { // Cleanup the type name to get rid of funny nested type names. string name = $"clr.{clrType.FullName}"; int i = name.LastIndexOf('+'); if (i > -1) { name = name.Substring(i + 1); } i = name.LastIndexOf('.'); if (i > -1) { name = name.Substring(i + 1); } IntPtr base_ = Runtime.PyBaseObjectType; if (clrType == typeof(Exception)) { base_ = Exceptions.Exception; } else if (clrType.BaseType != null) { ClassBase bc = ClassManager.GetClass(clrType.BaseType); if (bc.ObjectReference != null) { // there are cases when base class has not been fully initialized yet (nested types) base_ = bc.pyHandle; } } IntPtr type = AllocateTypeObject(name, Runtime.PyCLRMetaType); int newFieldOffset = InheritOrAllocateStandardFields(type, base_); if (ManagedType.IsManagedType(new BorrowedReference(base_))) { int baseClrInstOffset = Marshal.ReadInt32(base_, ManagedType.Offsets.tp_clr_inst_offset); Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, baseClrInstOffset); } else { Marshal.WriteInt32(type, ManagedType.Offsets.tp_clr_inst_offset, newFieldOffset); newFieldOffset += IntPtr.Size; } int ob_size = newFieldOffset; Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); // we want to do this after the slot stuff above in case the class itself implements a slot method SlotsHolder slotsHolder = CreateSolotsHolder(type); InitializeSlots(type, impl.GetType(), slotsHolder); if (Marshal.ReadIntPtr(type, TypeOffset.mp_length) == IntPtr.Zero && mp_length_slot.CanAssign(clrType)) { InitializeSlot(type, TypeOffset.mp_length, mp_length_slot.Method, slotsHolder); } if (!typeof(IEnumerable).IsAssignableFrom(clrType) && !typeof(IEnumerator).IsAssignableFrom(clrType)) { // The tp_iter slot should only be set for enumerable types. Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero); } // Only set mp_subscript and mp_ass_subscript for types with indexers if (!(impl is ArrayObject)) { if (impl.indexer == null || !impl.indexer.CanGet) { Marshal.WriteIntPtr(type, TypeOffset.mp_subscript, IntPtr.Zero); } if (impl.indexer == null || !impl.indexer.CanSet) { Marshal.WriteIntPtr(type, TypeOffset.mp_ass_subscript, IntPtr.Zero); } } if (base_ != IntPtr.Zero) { Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); Runtime.XIncref(base_); } const TypeFlags flags = TypeFlags.Default | TypeFlags.HasClrInstance | TypeFlags.HeapType | TypeFlags.BaseType | TypeFlags.HaveGC; Util.WriteCLong(type, TypeOffset.tp_flags, (int)flags); OperatorMethod.FixupSlots(type, clrType); // Leverage followup initialization from the Python runtime. Note // that the type of the new type must PyType_Type at the time we // call this, else PyType_Ready will skip some slot initialization. if (Runtime.PyType_Ready(type) != 0) { throw new PythonException(); } var dict = new BorrowedReference(Marshal.ReadIntPtr(type, TypeOffset.tp_dict)); string mn = clrType.Namespace ?? ""; var mod = NewReference.DangerousFromPointer(Runtime.PyString_FromString(mn)); Runtime.PyDict_SetItem(dict, PyIdentifier.__module__, mod); mod.Dispose(); var typeRef = new BorrowedReference(type); // Hide the gchandle of the implementation in a magic type slot. GCHandle gc = impl.AllocGCHandle(); ManagedType.InitGCHandle(typeRef, Runtime.CLRMetaType, gc); // Set the handle attributes on the implementing instance. impl.tpHandle = type; impl.pyHandle = type; //DebugUtil.DumpType(type); return(type); }