/// <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 explicit overload selection using subscript syntax ([]). /// </summary> public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { var self = (OverloadMapper)GetManagedObject(tp); // Note: if the type provides a non-generic method with N args // and a generic method that takes N params, then we always // prefer the non-generic version in doing overload selection. Type[] types = Runtime.PythonArgsToTypeArray(idx); if (types == null) { return(Exceptions.RaiseTypeError("type(s) expected")); } MethodInfo mi = MethodBinder.MatchSignature(self.m.info, types); if (mi == null) { var e = "No match found for signature"; return(Exceptions.RaiseTypeError(e)); } var mb = new MethodBinding(self.m, self.target) { info = mi }; return(mb.pyHandle); }
int IComparer.Compare(object m1, object m2) { var me1 = (MethodBase)m1; var me2 = (MethodBase)m2; if (me1.DeclaringType != me2.DeclaringType) { // m2's type derives from m1's type, favor m2 if (me1.DeclaringType.IsAssignableFrom(me2.DeclaringType)) { return(1); } // m1's type derives from m2's type, favor m1 if (me2.DeclaringType.IsAssignableFrom(me1.DeclaringType)) { return(-1); } } int p1 = MethodBinder.GetPrecedence((MethodBase)m1); int p2 = MethodBinder.GetPrecedence((MethodBase)m2); if (p1 < p2) { return(-1); } if (p1 > p2) { return(1); } return(0); }
/// <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()); }
//==================================================================== // This is a hack. Generally, no managed class is considered callable // from Python - with the exception of System.Delegate. It is useful // to be able to call a System.Delegate instance directly, especially // when working with multicast delegates. //==================================================================== public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); ClassBase cb = (ClassBase)GetManagedObject(tp); if (cb.type != typeof(System.Delegate)) { Exceptions.SetError(Exceptions.TypeError, "object is not callable"); return(IntPtr.Zero); } CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob); Delegate d = co.inst as Delegate; BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; MethodInfo method = d.GetType().GetMethod("Invoke", flags); MethodBinder binder = new MethodBinder(method); return(binder.Invoke(ob, args, kw)); }
public MethodObject(string name, MethodInfo[] info) : base() { this.name = name; this.info = info; binder = new MethodBinder(); for (int i = 0; i < info.Length; i++) { binder.AddMethod((MethodInfo)info[i]); } }
private void _MethodObject(string name, MethodInfo[] info) { this.name = name; this.info = info; binder = new MethodBinder(); for (int i = 0; i < info.Length; i++) { MethodInfo item = (MethodInfo)info[i]; binder.AddMethod(item); if (item.IsStatic) { this.is_static = true; } } }
private void _MethodObject(Type type, string name, MethodInfo[] info) { this.type = type; this.name = name; this.info = info; binder = new MethodBinder(); foreach (MethodInfo item in info) { binder.AddMethod(item); if (item.IsStatic) { this.is_static = true; } } }
int IComparer.Compare(Object m1, Object m2) { int p1 = MethodBinder.GetPrecedence((MethodBase)m1); int p2 = MethodBinder.GetPrecedence((MethodBase)m2); if (p1 < p2) { return(-1); } if (p1 > p2) { return(1); } return(0); }
//==================================================================== // MethodBinding __call__ implementation. //==================================================================== public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { MethodBinding self = (MethodBinding)GetManagedObject(ob); // This works around a situation where the wrong generic method is picked, // for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3) if (self.info != null) { if (self.info.IsGenericMethod) { int len = Runtime.PyTuple_Size(args); Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true); if (sigTp != null) { Type[] genericTp = self.info.GetGenericArguments(); MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp); if (betterMatch != null) { self.info = betterMatch; } } } } // This supports calling a method 'unbound', passing the instance // as the first argument. Note that this is not supported if any // of the overloads are static since we can't know if the intent // was to call the static method or the unbound instance method. if ((self.target == IntPtr.Zero) && (!self.m.IsStatic())) { int len = Runtime.PyTuple_Size(args); if (len < 1) { Exceptions.SetError(Exceptions.TypeError, "not enough arguments"); return(IntPtr.Zero); } IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len); IntPtr inst = Runtime.PyTuple_GetItem(args, 0); Runtime.Incref(inst); IntPtr r = self.m.Invoke(inst, uargs, kw, self.info); Runtime.Decref(inst); Runtime.Decref(uargs); return(r); } return(self.m.Invoke(self.target, args, kw, self.info)); }
int IComparer <MaybeMethodBase> .Compare(MaybeMethodBase m1, MaybeMethodBase m2) { MethodBase me1 = m1.UnsafeValue; MethodBase me2 = m2.UnsafeValue; if (me1 == null && me2 == null) { return(0); } else if (me1 == null) { return(-1); } else if (me2 == null) { return(1); } if (me1.DeclaringType != me2.DeclaringType) { // m2's type derives from m1's type, favor m2 if (me1.DeclaringType.IsAssignableFrom(me2.DeclaringType)) { return(1); } // m1's type derives from m2's type, favor m1 if (me2.DeclaringType.IsAssignableFrom(me1.DeclaringType)) { return(-1); } } int p1 = MethodBinder.GetPrecedence(me1); int p2 = MethodBinder.GetPrecedence(me2); if (p1 < p2) { return(-1); } if (p1 > p2) { return(1); } return(0); }
public MethodObject(MaybeType type, string name, MethodBase[] info, bool allow_threads = MethodBinder.DefaultAllowThreads) { this.type = type; this.name = name; this.infoList = new List <MaybeMethodInfo>(); binder = new MethodBinder(); foreach (MethodBase item in info) { this.infoList.Add(item); binder.AddMethod(item); if (item.IsStatic) { this.is_static = true; } } binder.allow_threads = allow_threads; }
public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { MethodBinding self = (MethodBinding)GetManagedObject(tp); MethodInfo sig = MethodBinder.MatchByTypeSig(self.m.info, idx); if (sig == null) { return(Exceptions.RaiseTypeError( "No match found for signature" )); } MethodBinding mb = new MethodBinding(self.m, self.target); mb.info = sig; Runtime.Incref(mb.pyHandle); return(mb.pyHandle); }
public Indexer() { GetterBinder = new MethodBinder(); SetterBinder = new MethodBinder(); }
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); }
internal DelegateObject(Type tp) : base(tp) { binder = new MethodBinder(tp.GetMethod("Invoke")); }
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); }
//==================================================================== // This is a hack. Generally, no managed class is considered callable // from Python - with the exception of System.Delegate. It is useful // to be able to call a System.Delegate instance directly, especially // when working with multicast delegates. //==================================================================== public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); ClassBase cb = (ClassBase)GetManagedObject(tp); if (cb.type != typeof(System.Delegate)) { Exceptions.SetError(Exceptions.TypeError, "object is not callable"); return IntPtr.Zero; } CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob); Delegate d = co.inst as Delegate; BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; MethodInfo method = d.GetType().GetMethod("Invoke", flags); MethodBinder binder = new MethodBinder(method); return binder.Invoke(ob, args, kw); }
/// <summary> /// MethodBinding __call__ implementation. /// </summary> public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { var self = (MethodBinding)GetManagedObject(ob); // This works around a situation where the wrong generic method is picked, // for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3) if (self.info != null) { if (self.info.IsGenericMethod) { var len = Runtime.PyTuple_Size(args); //FIXME: Never used Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true); if (sigTp != null) { Type[] genericTp = self.info.GetGenericArguments(); MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp); if (betterMatch != null) { self.info = betterMatch; } } } } // This supports calling a method 'unbound', passing the instance // as the first argument. Note that this is not supported if any // of the overloads are static since we can't know if the intent // was to call the static method or the unbound instance method. var disposeList = new List <IntPtr>(); try { IntPtr target = self.target; if (target == IntPtr.Zero && !self.m.IsStatic()) { var len = Runtime.PyTuple_Size(args); if (len < 1) { Exceptions.SetError(Exceptions.TypeError, "not enough arguments"); return(IntPtr.Zero); } target = Runtime.PyTuple_GetItem(args, 0); Runtime.XIncref(target); disposeList.Add(target); args = Runtime.PyTuple_GetSlice(args, 1, len); disposeList.Add(args); } // if the class is a IPythonDerivedClass and target is not the same as self.targetType // (eg if calling the base class method) then call the original base class method instead // of the target method. IntPtr superType = IntPtr.Zero; if (Runtime.PyObject_TYPE(target) != self.targetType) { var inst = GetManagedObject(target) as CLRObject; if (inst?.inst is IPythonDerivedType) { var baseType = GetManagedObject(self.targetType) as ClassBase; if (baseType != null) { string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name; IntPtr baseMethod = Runtime.PyObject_GetAttrString(target, baseMethodName); if (baseMethod != IntPtr.Zero) { var baseSelf = GetManagedObject(baseMethod) as MethodBinding; if (baseSelf != null) { self = baseSelf; } Runtime.XDecref(baseMethod); } else { Runtime.PyErr_Clear(); } } } } return(self.m.Invoke(target, args, kw, self.info)); } finally { foreach (IntPtr ptr in disposeList) { Runtime.XDecref(ptr); } } }