diff --git a/src/runtime/Converter.cs b/src/runtime/Converter.cs
index a90f31513..a99961aaa 100644
--- a/src/runtime/Converter.cs
+++ b/src/runtime/Converter.cs
@@ -550,7 +550,7 @@ internal static int ToInt32(BorrowedReference value)
///
/// Convert a Python value to an instance of a primitive managed type.
///
- private static bool ToPrimitive(BorrowedReference value, Type obType, out object? result, bool setError)
+ internal static bool ToPrimitive(BorrowedReference value, Type obType, out object? result, bool setError)
{
result = null;
if (obType.IsEnum)
diff --git a/src/runtime/PythonTypes/PyFloat.cs b/src/runtime/PythonTypes/PyFloat.cs
index 7fb9e8f4d..10104c10f 100644
--- a/src/runtime/PythonTypes/PyFloat.cs
+++ b/src/runtime/PythonTypes/PyFloat.cs
@@ -101,5 +101,7 @@ public static PyFloat AsFloat(PyObject value)
PythonException.ThrowIfIsNull(op);
return new PyFloat(op.Steal());
}
+
+ public override TypeCode GetTypeCode() => TypeCode.Double;
}
}
diff --git a/src/runtime/PythonTypes/PyInt.cs b/src/runtime/PythonTypes/PyInt.cs
index 3dcc6ddb2..6b3dbf210 100644
--- a/src/runtime/PythonTypes/PyInt.cs
+++ b/src/runtime/PythonTypes/PyInt.cs
@@ -230,5 +230,7 @@ public string ToString(string format, IFormatProvider formatProvider)
using var _ = Py.GIL();
return ToBigInteger().ToString(format, formatProvider);
}
+
+ public override TypeCode GetTypeCode() => TypeCode.Int64;
}
}
diff --git a/src/runtime/PythonTypes/PyObject.IConvertible.cs b/src/runtime/PythonTypes/PyObject.IConvertible.cs
new file mode 100644
index 000000000..503d3cab4
--- /dev/null
+++ b/src/runtime/PythonTypes/PyObject.IConvertible.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace Python.Runtime;
+
+public partial class PyObject : IConvertible
+{
+ public virtual TypeCode GetTypeCode() => TypeCode.Object;
+
+ private T DoConvert()
+ {
+ using var _ = Py.GIL();
+ if (Converter.ToPrimitive(Reference, typeof(T), out object? result, setError: false))
+ {
+ return (T)result!;
+ }
+ else
+ {
+ throw new InvalidCastException();
+ }
+ }
+
+ public bool ToBoolean(IFormatProvider provider) => DoConvert();
+ public byte ToByte(IFormatProvider provider) => DoConvert();
+ public char ToChar(IFormatProvider provider) => DoConvert();
+ public short ToInt16(IFormatProvider provider) => DoConvert();
+ public int ToInt32(IFormatProvider provider) => DoConvert();
+ public long ToInt64(IFormatProvider provider) => DoConvert();
+ public sbyte ToSByte(IFormatProvider provider) => DoConvert();
+ public ushort ToUInt16(IFormatProvider provider) => DoConvert();
+ public uint ToUInt32(IFormatProvider provider) => DoConvert();
+ public ulong ToUInt64(IFormatProvider provider) => DoConvert();
+
+ public float ToSingle(IFormatProvider provider) => DoConvert();
+ public double ToDouble(IFormatProvider provider) => DoConvert();
+
+ public string ToString(IFormatProvider provider) => DoConvert();
+
+ public DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException();
+ public decimal ToDecimal(IFormatProvider provider) => throw new InvalidCastException();
+
+ public object ToType(Type conversionType, IFormatProvider provider)
+ {
+ if (Converter.ToManaged(Reference, conversionType, out object? result, setError: false))
+ {
+ return result!;
+ }
+ else
+ {
+ throw new InvalidCastException();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/runtime/PythonTypes/PyString.cs b/src/runtime/PythonTypes/PyString.cs
index cdd45e2c3..d54397fcf 100644
--- a/src/runtime/PythonTypes/PyString.cs
+++ b/src/runtime/PythonTypes/PyString.cs
@@ -59,5 +59,7 @@ public static bool IsStringType(PyObject value)
{
return Runtime.PyString_Check(value.obj);
}
+
+ public override TypeCode GetTypeCode() => TypeCode.String;
}
}
diff --git a/tests/test_conversion.py b/tests/test_conversion.py
index 341b11b90..4de286b14 100644
--- a/tests/test_conversion.py
+++ b/tests/test_conversion.py
@@ -670,3 +670,10 @@ def test_int_param_resolution_required():
data = list(mri.MethodA(0x100000000, 10))
assert len(data) == 10
assert data[0] == 0
+
+def test_iconvertible_conversion():
+ change_type = System.Convert.ChangeType
+
+ assert 1024 == change_type(1024, System.Int32)
+ assert 1024 == change_type(1024, System.Int64)
+ assert 1024 == change_type(1024, System.Int16)