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,7 +631,18 @@ 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 ;
634
+ if ( value == Runtime . PyTrue )
635
+ {
636
+ result = true ;
637
+ }
638
+ else if ( value == Runtime . PyFalse )
639
+ {
640
+ result = false ;
641
+ }
642
+ else if ( setError )
643
+ {
644
+ goto type_error ;
645
+ }
594
646
return true ;
595
647
596
648
case TypeCode . Byte :
@@ -768,6 +820,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
768
820
769
821
case TypeCode . Single :
770
822
{
823
+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
824
+ {
825
+ goto type_error ;
826
+ }
771
827
double num = Runtime . PyFloat_AsDouble ( value ) ;
772
828
if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
773
829
{
@@ -786,6 +842,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
786
842
787
843
case TypeCode . Double :
788
844
{
845
+ if ( ! Runtime . PyFloat_Check ( value ) && ! Runtime . PyInt_Check ( value ) )
846
+ {
847
+ goto type_error ;
848
+ }
789
849
double num = Runtime . PyFloat_AsDouble ( value ) ;
790
850
if ( num == - 1.0 && Exceptions . ErrorOccurred ( ) )
791
851
{
@@ -933,6 +993,13 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool
933
993
result = items ;
934
994
return true ;
935
995
}
996
+
997
+ internal static bool IsFloatingNumber ( Type type ) => type == typeof ( float ) || type == typeof ( double ) ;
998
+ internal static bool IsInteger ( Type type )
999
+ => type == typeof ( Byte ) || type == typeof ( SByte )
1000
+ || type == typeof ( Int16 ) || type == typeof ( UInt16 )
1001
+ || type == typeof ( Int32 ) || type == typeof ( UInt32 )
1002
+ || type == typeof ( Int64 ) || type == typeof ( UInt64 ) ;
936
1003
}
937
1004
938
1005
public static class ConverterExtension
0 commit comments