2
2
using System ;
3
3
using System . Collections ;
4
4
using System . Collections . Generic ;
5
+ using System . Diagnostics ;
5
6
using System . Globalization ;
6
7
using System . Reflection ;
7
8
using System . Runtime . InteropServices ;
@@ -501,6 +502,44 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
501
502
return ToPrimitive ( value , obType , out result , setError ) ;
502
503
}
503
504
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
+
504
543
static object ? ToPyObjectSubclass ( ConstructorInfo ctor , PyObject instance , bool setError )
505
544
{
506
545
try
@@ -544,6 +583,8 @@ internal static int ToInt32(BorrowedReference value)
544
583
return checked ( ( int ) num ) ;
545
584
}
546
585
586
+ private static bool ToPrimitive ( BorrowedReference value , Type obType , out object ? result , bool setError )
587
+ => ToPrimitive ( value . DangerousGetAddress ( ) , obType , out result , setError ) ;
547
588
/// <summary>
548
589
/// Convert a Python value to an instance of a primitive managed type.
549
590
/// </summary>
@@ -590,8 +631,21 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
590
631
}
591
632
592
633
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 ;
595
649
596
650
case TypeCode . Byte :
597
651
{
@@ -768,6 +822,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
768
822
769
823
case TypeCode . Single :
770
824
{
825
+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
826
+ {
827
+ goto type_error ;
828
+ }
771
829
double num = Runtime . PyFloat_AsDouble ( value ) ;
772
830
if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
773
831
{
@@ -786,6 +844,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
786
844
787
845
case TypeCode . Double :
788
846
{
847
+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
848
+ {
849
+ goto type_error ;
850
+ }
789
851
double num = Runtime . PyFloat_AsDouble ( value ) ;
790
852
if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
791
853
{
@@ -933,6 +995,13 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool
933
995
result = items ;
934
996
return true ;
935
997
}
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 ) ;
936
1005
}
937
1006
938
1007
public static class ConverterExtension
0 commit comments