/// <summary> /// Determine the managed type that a Python argument object needs to be converted into. /// </summary> /// <param name="parameterType">The parameter's managed type.</param> /// <param name="argument">Pointer to the Python argument object.</param> /// <returns>null if conversion is not possible</returns> static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument) { // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary Type clrtype = null; IntPtr pyoptype; if (clrtype != null) { if ((parameterType != typeof(object)) && (parameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(parameterType); pyoptype = Runtime.PyObject_Type(argument); var typematch = false; if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = parameterType; } } if (!typematch) { // this takes care of enum values TypeCode parameterTypeCode = Type.GetTypeCode(parameterType); TypeCode clrTypeCode = Type.GetTypeCode(clrtype); if (parameterTypeCode == clrTypeCode) { typematch = true; clrtype = parameterType; } else { Exceptions.RaiseTypeError($"Expected {parameterTypeCode}, got {clrTypeCode}"); } } Runtime.XDecref(pyoptype); if (!typematch) { return(null); } } else { clrtype = parameterType; } } else { clrtype = parameterType; } return(clrtype); }
static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool needsResolution) { // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary Type clrtype = null; IntPtr pyoptype; if (needsResolution) { // HACK: each overload should be weighted in some way instead pyoptype = Runtime.PyObject_Type(argument); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { clrtype = Converter.GetTypeByAlias(pyoptype); } Runtime.XDecref(pyoptype); } if (clrtype != null) { var typematch = false; if ((parameterType != typeof(object)) && (parameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(parameterType); pyoptype = Runtime.PyObject_Type(argument); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = parameterType; } } if (!typematch) { // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(parameterType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = parameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { return(null); } } else { typematch = true; clrtype = parameterType; } } else { clrtype = parameterType; } return(clrtype); }
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; var isGeneric = false; ArrayList defaultArgList = null; if (info != null) { _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { _methods = GetMethods(); } Type clrtype; // TODO: Clean up foreach (MethodBase mi in _methods) { if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length; var match = false; int arrayStart = -1; var 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(pi[v].DefaultValue); } } } else if (pynargs > clrnargs && clrnargs > 0 && Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) { // This is a `foo(params object[] bar)` style method match = true; arrayStart = clrnargs - 1; } if (match) { var margs = new object[clrnargs]; for (var 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) { var typematch = false; if ((pi[n].ParameterType != typeof(object)) && (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 nullables var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType); if (underlyingType == null) { underlyingType = pi[n].ParameterType; } // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(underlyingType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = pi[n].ParameterType; } // this takes care of implicit conversions var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype }); if (opImplicit != null) { typematch = opImplicit.ReturnType == pi[n].ParameterType; 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' var 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 = 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 int pynargs = Runtime.PyTuple_Size(args); object arg; var isGeneric = false; ArrayList defaultArgList; Type clrtype; Binding bindingUsingImplicitConversion = null; var methods = info == null?GetMethods() : new List <MethodInformation>(1) { new MethodInformation(info, info.GetParameters()) }; // TODO: Clean up foreach (var methodInformation in methods) { var mi = methodInformation.MethodBase; var pi = methodInformation.ParameterInfo; if (mi.IsGenericMethod) { isGeneric = true; } int clrnargs = pi.Length; int arrayStart; if (CheckMethodArgumentsMatch(clrnargs, pynargs, pi, out arrayStart, out defaultArgList)) { var outs = 0; var margs = new object[clrnargs]; var usedImplicitConversion = false; for (var 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.Count > 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) { var typematch = false; if ((pi[n].ParameterType != typeof(object)) && (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 nullables var underlyingType = Nullable.GetUnderlyingType(pi[n].ParameterType); if (underlyingType == null) { underlyingType = pi[n].ParameterType; } // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(underlyingType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = pi[n].ParameterType; } // accepts non-decimal numbers in decimal parameters if (underlyingType == typeof(decimal)) { clrtype = pi[n].ParameterType; typematch = Converter.ToManaged(op, clrtype, out arg, false); } // this takes care of implicit conversions var opImplicit = pi[n].ParameterType.GetMethod("op_Implicit", new[] { clrtype }); if (opImplicit != null) { usedImplicitConversion = typematch = opImplicit.ReturnType == pi[n].ParameterType; 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' var 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; } var binding = new Binding(mi, target, margs, outs); if (usedImplicitConversion) { // lets just keep the first binding using implicit conversion // this is to respect method order/precedence if (bindingUsingImplicitConversion == null) { // in this case we will not return the binding yet in case there is a match // which does not use implicit conversions, which will return directly bindingUsingImplicitConversion = binding; } } else { return(binding); } } } // if we generated a binding using implicit conversion return it if (bindingUsingImplicitConversion != null) { return(bindingUsingImplicitConversion); } // 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 = 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) { // Relevant function variables used post conversion var isGeneric = false; Binding bindingUsingImplicitConversion = null; // If we have KWArgs create dictionary and collect them Dictionary <string, IntPtr> kwArgDict = null; if (kw != IntPtr.Zero) { var pyKwArgsCount = (int)Runtime.PyDict_Size(kw); kwArgDict = new Dictionary <string, IntPtr>(pyKwArgsCount); IntPtr keylist = Runtime.PyDict_Keys(kw); IntPtr valueList = Runtime.PyDict_Values(kw); for (int i = 0; i < pyKwArgsCount; ++i) { var keyStr = Runtime.GetManagedString(Runtime.PyList_GetItem(new BorrowedReference(keylist), i)); kwArgDict[keyStr] = Runtime.PyList_GetItem(new BorrowedReference(valueList), i).DangerousGetAddress(); } Runtime.XDecref(keylist); Runtime.XDecref(valueList); } // Fetch our methods we are going to attempt to match and bind too. var methods = info == null?GetMethods() : new List <MethodInformation>(1) { new MethodInformation(info, info.GetParameters()) }; foreach (var methodInformation in methods) { // Relevant method variables var mi = methodInformation.MethodBase; var pi = methodInformation.ParameterInfo; isGeneric = mi.IsGenericMethod; int pyArgCount = (int)Runtime.PyTuple_Size(args); // Special case for operators bool isOperator = OperatorMethod.IsOperatorMethod(mi); // Binary operator methods will have 2 CLR args but only one Python arg // (unary operators will have 1 less each), since Python operator methods are bound. isOperator = isOperator && pyArgCount == pi.Length - 1; bool isReverse = isOperator && OperatorMethod.IsReverse((MethodInfo)mi); // Only cast if isOperator. if (isReverse && OperatorMethod.IsComparisonOp((MethodInfo)mi)) { continue; // Comparison operators in Python have no reverse mode. } // Preprocessing pi to remove either the first or second argument. if (isOperator && !isReverse) { // The first Python arg is the right operand, while the bound instance is the left. // We need to skip the first (left operand) CLR argument. pi = pi.Skip(1).ToArray(); } else if (isOperator && isReverse) { // The first Python arg is the left operand. // We need to take the first CLR argument. pi = pi.Take(1).ToArray(); } // Must be done after IsOperator section int clrArgCount = pi.Length; if (CheckMethodArgumentsMatch(clrArgCount, pyArgCount, kwArgDict, pi, out bool paramsArray, out ArrayList defaultArgList)) { var outs = 0; var margs = new object[clrArgCount]; int paramsArrayIndex = paramsArray ? pi.Length - 1 : -1; // -1 indicates no paramsArray var usedImplicitConversion = false; // Conversion loop for each parameter for (int paramIndex = 0; paramIndex < clrArgCount; paramIndex++) { IntPtr op = IntPtr.Zero; // Python object to be converted; not yet set var parameter = pi[paramIndex]; // Clr parameter we are targeting object arg; // Python -> Clr argument // Check our KWargs for this parameter bool hasNamedParam = kwArgDict == null ? false : kwArgDict.TryGetValue(parameter.Name, out op); bool isNewReference = false; // Check if we are going to use default if (paramIndex >= pyArgCount && !(hasNamedParam || (paramsArray && paramIndex == paramsArrayIndex))) { if (defaultArgList != null) { margs[paramIndex] = defaultArgList[paramIndex - pyArgCount]; } continue; } // At this point, if op is IntPtr.Zero we don't have a KWArg and are not using default if (op == IntPtr.Zero) { // If we have reached the paramIndex if (paramsArrayIndex == paramIndex) { op = HandleParamsArray(args, paramsArrayIndex, pyArgCount, out isNewReference); } else { op = Runtime.PyTuple_GetItem(args, paramIndex); } } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary Type clrtype = null; IntPtr pyoptype; if (methods.Count > 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) { var typematch = false; if ((parameter.ParameterType != typeof(object)) && (parameter.ParameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(parameter.ParameterType); pyoptype = Runtime.PyObject_Type(op); Exceptions.Clear(); if (pyoptype != IntPtr.Zero) { if (pytype != pyoptype) { typematch = false; } else { typematch = true; clrtype = parameter.ParameterType; } } if (!typematch) { // this takes care of nullables var underlyingType = Nullable.GetUnderlyingType(parameter.ParameterType); if (underlyingType == null) { underlyingType = parameter.ParameterType; } // this takes care of enum values TypeCode argtypecode = Type.GetTypeCode(underlyingType); TypeCode paramtypecode = Type.GetTypeCode(clrtype); if (argtypecode == paramtypecode) { typematch = true; clrtype = parameter.ParameterType; } // accepts non-decimal numbers in decimal parameters if (underlyingType == typeof(decimal)) { clrtype = parameter.ParameterType; typematch = Converter.ToManaged(op, clrtype, out arg, false); } // this takes care of implicit conversions var opImplicit = parameter.ParameterType.GetMethod("op_Implicit", new[] { clrtype }); if (opImplicit != null) { usedImplicitConversion = typematch = opImplicit.ReturnType == parameter.ParameterType; clrtype = parameter.ParameterType; } } Runtime.XDecref(pyoptype); if (!typematch) { margs = null; break; } } else { clrtype = parameter.ParameterType; } } else { clrtype = parameter.ParameterType; } if (parameter.IsOut || clrtype.IsByRef) { outs++; } if (!Converter.ToManaged(op, clrtype, out arg, false)) { Exceptions.Clear(); margs = null; break; } if (isNewReference) { // TODO: is this a bug? Should this happen even if the conversion fails? // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(op); } margs[paramIndex] = arg; } if (margs == null) { continue; } if (isOperator) { if (inst != IntPtr.Zero) { if (ManagedType.GetManagedObject(inst) is CLRObject co) { bool isUnary = pyArgCount == 0; // Postprocessing to extend margs. var margsTemp = isUnary ? new object[1] : new object[2]; // If reverse, the bound instance is the right operand. int boundOperandIndex = isReverse ? 1 : 0; // If reverse, the passed instance is the left operand. int passedOperandIndex = isReverse ? 0 : 1; margsTemp[boundOperandIndex] = co.inst; if (!isUnary) { margsTemp[passedOperandIndex] = margs[0]; } margs = margsTemp; } else { 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' var 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; } var binding = new Binding(mi, target, margs, outs); if (usedImplicitConversion) { // lets just keep the first binding using implicit conversion // this is to respect method order/precedence if (bindingUsingImplicitConversion == null) { // in this case we will not return the binding yet in case there is a match // which does not use implicit conversions, which will return directly bindingUsingImplicitConversion = binding; } } else { return(binding); } } } // if we generated a binding using implicit conversion return it if (bindingUsingImplicitConversion != null) { return(bindingUsingImplicitConversion); } // 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 = MatchParameters(methodinfo, types); return(Bind(inst, args, kw, mi, null)); } return(null); }
internal Binding Bind(IntPtr inst, IntPtr pythonParametersPtr, IntPtr kw, MethodBase info, MethodInfo[] methodInfoArray) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; // NOTE: return the size of the args pointer (the number of parameter from the python call) int pythonParameterCount = Runtime.PyTuple_Size(pythonParametersPtr); //WHY: Why is that so widely scoped ? object pythonManagedParameterPtr; var isGeneric = false; ArrayList defaultParameterList = null; if (info != null) { // NOTE: If a MethodBase object has been provided, create an array with only it. // WHY a method base is provided some times and not other ? (ex: when call a genric with a type in []) _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else { // NOTE: Create an array of MethodBase from teh called method/constructor // WHY not use the methodinfo provided? _methods = GetMethods(); } //WHY is it so widely scoped Type clrConvertedParameterType; // TODO: Clean up foreach (MethodBase methodInfo in _methods) { //WHY not just do isGeneric = mi.IsGenericMethod or use it directly ? if (methodInfo.IsGenericMethod) { isGeneric = true; } //NOTE: Get the parameter from the current MethodBase //NOTE: MethodInfo Ok ParameterInfo[] clrParameterInfoArray = methodInfo.GetParameters(); //NOTE: Get the number of clr parameters int clrParameterCount = clrParameterInfoArray.Length; var paramCountMatch = false; //REFACTOR: Use var like the other local variables var clrHasParamArray = false; var clrParamsArrayStart = -1; var byRefCount = 0; if (pythonParameterCount == clrParameterCount) { paramCountMatch = true; } else if (pythonParameterCount < clrParameterCount) { paramCountMatch = true; defaultParameterList = new ArrayList(); for (int v = pythonParameterCount; v < clrParameterCount; v++) { if (clrParameterInfoArray[v].DefaultValue == DBNull.Value) { paramCountMatch = false; } else { defaultParameterList.Add(clrParameterInfoArray[v].DefaultValue); } } } else if (pythonParameterCount > clrParameterCount && clrParameterCount > 0 && Attribute.IsDefined(clrParameterInfoArray[clrParameterCount - 1], typeof(ParamArrayAttribute))) { // This is a `foo({...}, params object[] bar)` style method paramCountMatch = true; clrHasParamArray = true; clrParamsArrayStart = clrParameterCount - 1; } if (paramCountMatch) { var methodParametersPtrArray = new object[clrParameterCount]; for (var n = 0; n < clrParameterCount; n++) { IntPtr pythonParameterPtr; if (n < pythonParameterCount) { if (clrParamsArrayStart == n) { // map remaining Python arguments to a tuple since // the managed function accepts it - hopefully :] //WHY: Hmmm it returns a lot of python paramter as one. isn't there a problem later ? pythonParameterPtr = Runtime.PyTuple_GetSlice(pythonParametersPtr, clrParamsArrayStart, pythonParameterCount); } else { pythonParameterPtr = Runtime.PyTuple_GetItem(pythonParametersPtr, n); } // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary clrConvertedParameterType = null; IntPtr pythonParameterPtrType = IntPtr.Zero; if (_methods.Length > 1) { pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr); Exceptions.Clear(); if (pythonParameterPtrType != IntPtr.Zero) { clrConvertedParameterType = Converter.GetTypeByAlias(pythonParameterPtrType); } Runtime.XDecref(pythonParameterPtrType); } if (clrConvertedParameterType != null) { var parameterTypeMatch = false; if ((clrParameterInfoArray[n].ParameterType != typeof(object)) && (clrParameterInfoArray[n].ParameterType != clrConvertedParameterType)) { IntPtr pythonConvertedParameterPtrType = Converter.GetPythonTypeByAlias(clrParameterInfoArray[n].ParameterType); pythonParameterPtrType = Runtime.PyObject_Type(pythonParameterPtr); Exceptions.Clear(); if (pythonParameterPtrType != IntPtr.Zero) { if (pythonConvertedParameterPtrType != pythonParameterPtrType) { parameterTypeMatch = false; } else { parameterTypeMatch = true; clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } } if (!parameterTypeMatch) { // this takes care of enum values TypeCode clrParameterTypeCode = Type.GetTypeCode(clrParameterInfoArray[n].ParameterType); TypeCode clrConvertedParameterTypeCode = Type.GetTypeCode(clrConvertedParameterType); if (clrParameterTypeCode == clrConvertedParameterTypeCode) { parameterTypeMatch = true; clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } } Runtime.XDecref(pythonParameterPtrType); if (!parameterTypeMatch) { methodParametersPtrArray = null; break; } } else { parameterTypeMatch = true; clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } } else { clrConvertedParameterType = clrParameterInfoArray[n].ParameterType; } if (clrParameterInfoArray[n].IsOut || clrConvertedParameterType.IsByRef) { byRefCount++; } if (!Converter.ToManaged(pythonParameterPtr, clrConvertedParameterType, out pythonManagedParameterPtr, false)) { Exceptions.Clear(); methodParametersPtrArray = null; break; } if (clrParamsArrayStart == n) { // GetSlice() creates a new reference but GetItem() // returns only a borrow reference. Runtime.XDecref(pythonParameterPtr); } methodParametersPtrArray[n] = pythonParameterPtr; } else { if (defaultParameterList != null) { methodParametersPtrArray[n] = defaultParameterList[n - pythonParameterCount]; } } } if (methodParametersPtrArray == null) { continue; } object target = null; if (!methodInfo.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' var 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(methodInfo, target, methodParametersPtrArray, byRefCount)); } } // 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 && methodInfoArray != null) { Type[] types = Runtime.PythonArgsToTypeArray(pythonParametersPtr, true); MethodInfo mi = MatchParameters(methodInfoArray, types); return(Bind(inst, pythonParametersPtr, kw, mi, null)); } return(null); }