private object?TrueDispatch(object?[] args) { MethodInfo method = dtype.GetMethod("Invoke"); ParameterInfo[] pi = method.GetParameters(); Type rtype = method.ReturnType; NewReference callResult; using (var pyargs = Runtime.PyTuple_New(pi.Length)) { for (var i = 0; i < pi.Length; i++) { // Here we own the reference to the Python value, and we // give the ownership to the arg tuple. using var arg = Converter.ToPython(args[i], pi[i].ParameterType); int res = Runtime.PyTuple_SetItem(pyargs.Borrow(), i, arg.StealOrThrow()); if (res != 0) { throw PythonException.ThrowLastAsClrException(); } } callResult = Runtime.PyObject_Call(target, pyargs.Borrow(), null); } if (callResult.IsNull()) { throw PythonException.ThrowLastAsClrException(); } using (callResult) { BorrowedReference op = callResult.Borrow(); int byRefCount = pi.Count(parameterInfo => parameterInfo.ParameterType.IsByRef); if (byRefCount > 0) { // By symmetry with MethodBinder.Invoke, when there are out // parameters we expect to receive a tuple containing // the result, if any, followed by the out parameters. If there is only // one out parameter and the return type of the method is void, // we instead receive the out parameter as the result from Python. bool isVoid = rtype == typeof(void); int tupleSize = byRefCount + (isVoid ? 0 : 1); if (isVoid && byRefCount == 1) { // The return type is void and there is a single out parameter. for (int i = 0; i < pi.Length; i++) { Type t = pi[i].ParameterType; if (t.IsByRef) { if (!Converter.ToManaged(op, t, out args[i], true)) { Exceptions.RaiseTypeError($"The Python function did not return {t.GetElementType()} (the out parameter type)"); throw PythonException.ThrowLastAsClrException(); } break; } } return(null); } else if (Runtime.PyTuple_Check(op) && Runtime.PyTuple_Size(op) == tupleSize) { int index = isVoid ? 0 : 1; for (int i = 0; i < pi.Length; i++) { Type t = pi[i].ParameterType; if (t.IsByRef) { BorrowedReference item = Runtime.PyTuple_GetItem(op, index++); if (!Converter.ToManaged(item, t, out args[i], true)) { Exceptions.RaiseTypeError($"The Python function returned a tuple where element {i} was not {t.GetElementType()} (the out parameter type)"); throw PythonException.ThrowLastAsClrException(); } } } if (isVoid) { return(null); } BorrowedReference item0 = Runtime.PyTuple_GetItem(op, 0); if (!Converter.ToManaged(item0, rtype, out object?result0, true)) { Exceptions.RaiseTypeError($"The Python function returned a tuple where element 0 was not {rtype} (the return type)"); throw PythonException.ThrowLastAsClrException(); } return(result0); } else { string tpName = Runtime.PyObject_GetTypeName(op); if (Runtime.PyTuple_Check(op)) { tpName += $" of size {Runtime.PyTuple_Size(op)}"; } var sb = new StringBuilder(); if (!isVoid) { sb.Append(rtype.FullName); } for (int i = 0; i < pi.Length; i++) { Type t = pi[i].ParameterType; if (t.IsByRef) { if (sb.Length > 0) { sb.Append(","); } sb.Append(t.GetElementType().FullName); } } string returnValueString = isVoid ? "" : "the return value and "; Exceptions.RaiseTypeError($"Expected a tuple ({sb}) of {returnValueString}the values for out and ref parameters, got {tpName}."); throw PythonException.ThrowLastAsClrException(); } } if (rtype == typeof(void)) { return(null); } if (!Converter.ToManaged(op, rtype, out object?result, true)) { throw PythonException.ThrowLastAsClrException(); } return(result); } }
internal ReflectedClrType(BorrowedReference original) : base(original) { }
internal UnsafeReferenceWithRun(BorrowedReference pyObj) { RawObj = pyObj.DangerousGetAddressOrNull(); Run = Runtime.GetRun(); }
internal static Exception?ToException(BorrowedReference ob) { var co = GetManagedObject(ob) as CLRObject; return(co?.inst as Exception); }