/// <summary> /// Implement binding of generic methods using the subscript syntax []. /// </summary> public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { var self = (MethodBinding)GetManagedObject(tp); Type[] types = Runtime.PythonArgsToTypeArray(idx); if (types == null) { return(Exceptions.RaiseTypeError("type(s) expected")); } MethodInfo mi = MethodBinder.MatchParameters(self.m.info, types); if (mi == null) { return(Exceptions.RaiseTypeError("No match found for given type params")); } var mb = new MethodBinding(self.m, self.target) { info = mi }; Runtime.XIncref(mb.pyHandle); return(mb.pyHandle); }
/// <summary> /// Implement binding of generic methods using the subscript syntax []. /// </summary> public static NewReference mp_subscript(BorrowedReference tp, BorrowedReference idx) { var self = (MethodBinding)GetManagedObject(tp) !; Type[]? types = Runtime.PythonArgsToTypeArray(idx); if (types == null) { return(Exceptions.RaiseTypeError("type(s) expected")); } MethodBase[] overloads = self.m.IsInstanceConstructor ? self.m.type.Value.GetConstructor(types) is { } ctor ? new[] { ctor } : Array.Empty <MethodBase>() : MethodBinder.MatchParameters(self.m.info, types); if (overloads.Length == 0) { return(Exceptions.RaiseTypeError("No match found for given type params")); } MethodObject overloaded = self.m.WithOverloads(overloads); var mb = new MethodBinding(overloaded, self.target, self.targetType); return(mb.Alloc()); }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; int pynargs = Runtime.PyTuple_Size(args); object arg; bool isGeneric = false; if (info != null) { _methods = (MethodBase[])Array.CreateInstance( typeof(MethodBase), 1 ); _methods.SetValue(info, 0); } else { _methods = GetMethods(); } for (int i = 0; i < _methods.Length; i++) { MethodBase mi = _methods[i]; if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length; bool match = false; int arrayStart = -1; int outs = 0; if (pynargs == clrnargs) { match = true; } else if ((pynargs > clrnargs) && (clrnargs > 0) && (pi[clrnargs - 1].ParameterType.IsArray)) { // The last argument of the mananged functions seems to // accept multiple arguments as a array. Hopefully it's a // spam(params object[] egg) style method match = true; arrayStart = clrnargs - 1; } if (match) { Object[] margs = new Object[clrnargs]; for (int n = 0; n < clrnargs; n++) { IntPtr op; if (arrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs); } else { op = Runtime.PyTuple_GetItem(args, n); } Type type = pi[n].ParameterType; if (pi[n].IsOut || type.IsByRef) { outs++; } if (!Converter.ToManaged(op, type, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (arrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.Decref(op); } margs[n] = arg; } if (margs == null) { continue; } Object target = null; if ((!mi.IsStatic) && (inst != IntPtr.Zero)) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } return(new Binding(mi, target, margs, outs)); } } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && (info == null) && (methodinfo != null)) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; int pynargs = Runtime.PyTuple_Size(args); object arg; bool isGeneric = false; ArrayList defaultArgList = null; if (info != null) { _methods = (MethodBase[])Array.CreateInstance( typeof(MethodBase), 1 ); _methods.SetValue(info, 0); } else { _methods = GetMethods(); } Type clrtype; for (int i = 0; i < _methods.Length; i++) { MethodBase mi = _methods[i]; if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length; bool match = false; int arrayStart = -1; int outs = 0; if (pynargs == clrnargs) { match = true; } else if (pynargs < clrnargs) { match = true; defaultArgList = new ArrayList(); for (int v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) { match = false; } else { defaultArgList.Add((object)pi[v].DefaultValue); } } } else if ((pynargs > clrnargs) && (clrnargs > 0) && Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) { // This is a spam(params object[] egg) style method match = true; arrayStart = clrnargs - 1; } if (match) { Object[] margs = new Object[clrnargs]; for (int n = 0; n < clrnargs; n++) { IntPtr op; if (n < pynargs) { if (arrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs); } else { op = Runtime.PyTuple_GetItem(args, n); } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary clrtype = null; IntPtr pyoptype; if (_methods.Length > 1) { pyoptype = IntPtr.Zero; pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { clrtype = Converter.GetTypeByAlias(pyoptype); } Runtime.XDecref(pyoptype); } if (clrtype != null) { bool typematch = false; if (pi[n].ParameterType != clrtype) { IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType); pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = pi[n].ParameterType; } } if (!typematch) { // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(pi[n].ParameterType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = pi[n].ParameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { margs = null; break; } } else { typematch = true; clrtype = pi[n].ParameterType; } } else { clrtype = pi[n].ParameterType; } if (pi[n].IsOut || clrtype.IsByRef) { outs++; } if (!Converter.ToManaged(op, clrtype, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (arrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(op); } margs[n] = arg; } else { if (defaultArgList != null) { margs[n] = defaultArgList[n - pynargs]; } } } if (margs == null) { continue; } Object target = null; if ((!mi.IsStatic) && (inst != IntPtr.Zero)) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method // on the class rather than on an instance of the class. // XXX maybe better to do this before all the other rigmarole. if (co == null) { return(null); } target = co.inst; } return(new Binding(mi, target, margs, outs)); } } // We weren't able to find a matching method but at least one // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. if (isGeneric && (info == null) && (methodinfo != null)) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }