22using System ;
33using System . Collections ;
44using System . Collections . Generic ;
5+ using System . Diagnostics ;
56using System . Globalization ;
67using System . Reflection ;
78using System . Runtime . InteropServices ;
@@ -501,6 +502,44 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
501502 return ToPrimitive ( value , obType , out result , setError ) ;
502503 }
503504
505+ /// <remarks>
506+ /// Unlike <see cref="ToManaged(BorrowedReference, Type, out object?, bool)"/>,
507+ /// this method does not have a <c>setError</c> parameter, because it should
508+ /// only be called after <see cref="ToManaged(BorrowedReference, Type, out object?, bool)"/>.
509+ /// </remarks>
510+ internal static bool ToManagedExplicit ( BorrowedReference value , Type obType ,
511+ out object ? result )
512+ {
513+ result = null ;
514+
515+ // this method would potentially clean any existing error resulting in information loss
516+ Debug . Assert ( Runtime . PyErr_Occurred ( ) == null ) ;
517+
518+ string ? converterName =
519+ IsInteger ( obType ) ? "__int__"
520+ : IsFloatingNumber ( obType ) ? "__float__"
521+ : null ;
522+
523+ if ( converterName is null ) return false ;
524+
525+ Debug . Assert ( obType . IsPrimitive ) ;
526+
527+ using var converter = Runtime . PyObject_GetAttrString ( value , converterName ) ;
528+ if ( converter . IsNull ( ) )
529+ {
530+ Exceptions . Clear ( ) ;
531+ return false ;
532+ }
533+
534+ using var explicitlyCoerced = Runtime . PyObject_CallObject ( converter , BorrowedReference . Null ) ;
535+ if ( explicitlyCoerced . IsNull ( ) )
536+ {
537+ Exceptions . Clear ( ) ;
538+ return false ;
539+ }
540+ return ToPrimitive ( explicitlyCoerced , obType , out result , false ) ;
541+ }
542+
504543 static object ? ToPyObjectSubclass ( ConstructorInfo ctor , PyObject instance , bool setError )
505544 {
506545 try
@@ -544,6 +583,8 @@ internal static int ToInt32(BorrowedReference value)
544583 return checked ( ( int ) num ) ;
545584 }
546585
586+ private static bool ToPrimitive ( BorrowedReference value , Type obType , out object ? result , bool setError )
587+ => ToPrimitive ( value . DangerousGetAddress ( ) , obType , out result , setError ) ;
547588 /// <summary>
548589 /// Convert a Python value to an instance of a primitive managed type.
549590 /// </summary>
@@ -590,8 +631,21 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
590631 }
591632
592633 case TypeCode . Boolean :
593- result = Runtime . PyObject_IsTrue ( value ) != 0 ;
594- return true ;
634+ if ( value == Runtime . PyTrue )
635+ {
636+ result = true ;
637+ return true ;
638+ }
639+ if ( value == Runtime . PyFalse )
640+ {
641+ result = false ;
642+ return true ;
643+ }
644+ if ( setError )
645+ {
646+ goto type_error ;
647+ }
648+ return false ;
595649
596650 case TypeCode . Byte :
597651 {
@@ -768,6 +822,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
768822
769823 case TypeCode . Single :
770824 {
825+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
826+ {
827+ goto type_error ;
828+ }
771829 double num = Runtime . PyFloat_AsDouble ( value ) ;
772830 if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
773831 {
@@ -786,6 +844,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
786844
787845 case TypeCode . Double :
788846 {
847+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
848+ {
849+ goto type_error ;
850+ }
789851 double num = Runtime . PyFloat_AsDouble ( value ) ;
790852 if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
791853 {
@@ -933,6 +995,13 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool
933995 result = items ;
934996 return true ;
935997 }
998+
999+ internal static bool IsFloatingNumber ( Type type ) => type == typeof ( float ) || type == typeof ( double ) ;
1000+ internal static bool IsInteger ( Type type )
1001+ => type == typeof ( Byte ) || type == typeof ( SByte )
1002+ || type == typeof ( Int16 ) || type == typeof ( UInt16 )
1003+ || type == typeof ( Int32 ) || type == typeof ( UInt32 )
1004+ || type == typeof ( Int64 ) || type == typeof ( UInt64 ) ;
9361005 }
9371006
9381007 public static class ConverterExtension
0 commit comments