X Tutup
using System; using System.Linq; using System.Reflection; namespace Python.Runtime { /// /// Managed class that provides the implementation for reflected types. /// Managed classes and value types are represented in Python by actual /// Python type objects. Each of those type objects is associated with /// an instance of ClassObject, which provides its implementation. /// [Serializable] internal class ClassObject : ClassBase { internal ConstructorBinder binder; internal int NumCtors = 0; internal ClassObject(Type tp) : base(tp) { var _ctors = type.Value.GetConstructors(); NumCtors = _ctors.Length; binder = new ConstructorBinder(type.Value); foreach (ConstructorInfo t in _ctors) { binder.AddMethod(t); } } /// /// Helper to get docstring from reflected constructor info. /// internal NewReference GetDocString() { MethodBase[] methods = binder.GetMethods(); var str = ""; foreach (MethodBase t in methods) { if (str.Length > 0) { str += Environment.NewLine; } str += t.ToString(); } return Runtime.PyString_FromString(str); } /// /// Implements __new__ for reflected classes and value types. /// public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference kw) { var self = GetManagedObject(tp) as ClassObject; // Sanity check: this ensures a graceful error if someone does // something intentially wrong like use the managed metatype for // a class that is not really derived from a managed class. if (self == null) { return Exceptions.RaiseTypeError("invalid object"); } if (!self.type.Valid) { return Exceptions.RaiseTypeError(self.type.DeletedMessage); } Type type = self.type.Value; // Primitive types do not have constructors, but they look like // they do from Python. If the ClassObject represents one of the // convertible primitive types, just convert the arg directly. if (type.IsPrimitive || type == typeof(string)) { if (Runtime.PyTuple_Size(args) != 1) { Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments"); return default; } BorrowedReference op = Runtime.PyTuple_GetItem(args, 0); if (!Converter.ToManaged(op, type, out var result, true)) { return default; } return CLRObject.GetReference(result!, tp); } if (type.IsAbstract) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class"); return default; } if (type.IsEnum) { return NewEnum(type, args, tp); } object? obj = self.binder.InvokeRaw(null, args, kw); if (obj == null) { return default; } return CLRObject.GetReference(obj, tp); } private static NewReference NewEnum(Type type, BorrowedReference args, BorrowedReference tp) { nint argCount = Runtime.PyTuple_Size(args); bool allowUnchecked = false; if (argCount == 2) { var allow = Runtime.PyTuple_GetItem(args, 1); if (!Converter.ToManaged(allow, typeof(bool), out var allowObj, true) || allowObj is null) { Exceptions.RaiseTypeError("second argument to enum constructor must be a boolean"); return default; } allowUnchecked |= (bool)allowObj; } if (argCount < 1 || argCount > 2) { Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments"); return default; } var op = Runtime.PyTuple_GetItem(args, 0); if (!Converter.ToManaged(op, type.GetEnumUnderlyingType(), out object? result, true)) { return default; } if (!allowUnchecked && !Enum.IsDefined(type, result) && !type.IsFlagsEnum()) { Exceptions.SetError(Exceptions.ValueError, "Invalid enumeration value. Pass True as the second argument if unchecked conversion is desired"); return default; } object enumValue = Enum.ToObject(type, result); return CLRObject.GetReference(enumValue, tp); } /// /// Implementation of [] semantics for reflected types. This exists /// both to implement the Array[int] syntax for creating arrays and /// to support generic name overload resolution using []. /// public override NewReference type_subscript(BorrowedReference idx) { if (!type.Valid) { return Exceptions.RaiseTypeError(type.DeletedMessage); } // If this type is the Array type, the [] means we need to // construct and return an array type of the given element type. if (type.Value == typeof(Array)) { if (Runtime.PyTuple_Check(idx)) { return Exceptions.RaiseTypeError("type expected"); } var c = GetManagedObject(idx) as ClassBase; Type? t = c != null ? c.type.Value : Converter.GetTypeByAlias(idx); if (t == null) { return Exceptions.RaiseTypeError("type expected"); } Type a = t.MakeArrayType(); PyType o = ClassManager.GetClass(a); return new NewReference(o); } // If there are generics in our namespace with the same base name // as the current type, then [] means the caller wants to // bind the generic type matching the given type parameters. Type[]? types = Runtime.PythonArgsToTypeArray(idx); if (types == null) { return Exceptions.RaiseTypeError("type(s) expected"); } Type gtype = AssemblyManager.LookupTypes($"{type.Value.FullName}`{types.Length}").FirstOrDefault(); if (gtype != null) { var g = (GenericType)ClassManager.GetClassImpl(gtype); return g.type_subscript(idx); } return Exceptions.RaiseTypeError("unsubscriptable object"); } } }
X Tutup