8
8
// ==========================================================================
9
9
10
10
using System ;
11
+ using System . Dynamic ;
12
+ using System . Linq . Expressions ;
11
13
12
14
namespace Python . Runtime {
13
15
@@ -17,7 +19,7 @@ namespace Python.Runtime {
17
19
/// http://www.python.org/doc/current/api/object.html for details.
18
20
/// </summary>
19
21
20
- public class PyObject : IDisposable {
22
+ public class PyObject : DynamicObject , IDisposable {
21
23
22
24
protected internal IntPtr obj = IntPtr . Zero ;
23
25
private bool disposed = false ;
@@ -95,7 +97,7 @@ public static PyObject FromManagedObject(object ob) {
95
97
96
98
public object AsManagedObject ( Type t ) {
97
99
Object result ;
98
- if ( ! Converter . ToManaged ( this . Handle , t , out result , false ) ) {
100
+ if ( ! Converter . ToManaged ( this . obj , t , out result , false ) ) {
99
101
throw new InvalidCastException ( "cannot convert object to target type" ) ;
100
102
}
101
103
return result ;
@@ -609,7 +611,7 @@ public PyObject Invoke(PyTuple args) {
609
611
610
612
public PyObject Invoke ( PyObject [ ] args , PyDict kw ) {
611
613
PyTuple t = new PyTuple ( args ) ;
612
- IntPtr r = Runtime . PyObject_Call ( obj , t . obj , kw . obj ) ;
614
+ IntPtr r = Runtime . PyObject_Call ( obj , t . obj , kw != null ? kw . obj : IntPtr . Zero ) ;
613
615
t . Dispose ( ) ;
614
616
if ( r == IntPtr . Zero ) {
615
617
throw new PythonException ( ) ;
@@ -628,7 +630,7 @@ public PyObject Invoke(PyObject[] args, PyDict kw) {
628
630
/// </remarks>
629
631
630
632
public PyObject Invoke ( PyTuple args , PyDict kw ) {
631
- IntPtr r = Runtime . PyObject_Call ( obj , args . obj , kw . obj ) ;
633
+ IntPtr r = Runtime . PyObject_Call ( obj , args . obj , kw != null ? kw . obj : IntPtr . Zero ) ;
632
634
if ( r == IntPtr . Zero ) {
633
635
throw new PythonException ( ) ;
634
636
}
@@ -862,8 +864,222 @@ public override int GetHashCode() {
862
864
return Runtime . PyObject_Hash ( obj ) . ToInt32 ( ) ;
863
865
}
864
866
867
+ public override bool TryGetMember ( GetMemberBinder binder , out object result )
868
+ {
869
+ if ( this . HasAttr ( binder . Name ) )
870
+ {
871
+ result = this . GetAttr ( binder . Name ) ;
872
+ return true ;
873
+ }
874
+ else
875
+ return base . TryGetMember ( binder , out result ) ;
876
+ }
877
+
878
+ public override bool TrySetMember ( SetMemberBinder binder , object value )
879
+ {
880
+ if ( this . HasAttr ( binder . Name ) )
881
+ {
882
+ this . SetAttr ( binder . Name , ( PyObject ) value ) ;
883
+ return true ;
884
+ }
885
+ else
886
+ return base . TrySetMember ( binder , value ) ;
887
+ }
888
+
889
+ private void GetArgs ( object [ ] inargs , out PyTuple args , out PyDict kwargs )
890
+ {
891
+ int arg_count ;
892
+ for ( arg_count = 0 ; arg_count < inargs . Length && ! ( inargs [ arg_count ] is Py . KeywordArguments ) ; ++ arg_count ) ;
893
+ IntPtr argtuple = Runtime . PyTuple_New ( arg_count ) ;
894
+ for ( int i = 0 ; i < arg_count ; i ++ )
895
+ {
896
+ IntPtr ptr ;
897
+ if ( inargs [ i ] is PyObject )
898
+ {
899
+ ptr = ( ( PyObject ) inargs [ i ] ) . Handle ;
900
+ Runtime . Incref ( ptr ) ;
901
+ }
902
+ else
903
+ {
904
+ ptr = Converter . ToPython ( inargs [ i ] , inargs [ i ] . GetType ( ) ) ;
905
+ }
906
+ if ( Runtime . PyTuple_SetItem ( argtuple , i , ptr ) < 0 )
907
+ throw new PythonException ( ) ;
908
+ }
909
+ args = new PyTuple ( argtuple ) ;
910
+ kwargs = null ;
911
+ for ( int i = arg_count ; i < inargs . Length ; i ++ )
912
+ {
913
+ if ( ! ( inargs [ i ] is Py . KeywordArguments ) )
914
+ throw new ArgumentException ( "Keyword arguments must come after normal arguments." ) ;
915
+ if ( kwargs == null )
916
+ kwargs = ( Py . KeywordArguments ) inargs [ i ] ;
917
+ else
918
+ kwargs . Update ( ( Py . KeywordArguments ) inargs [ i ] ) ;
919
+ }
920
+ }
865
921
922
+ public override bool TryInvokeMember ( InvokeMemberBinder binder , object [ ] args , out object result )
923
+ {
924
+ if ( this . HasAttr ( binder . Name ) && this . GetAttr ( binder . Name ) . IsCallable ( ) )
925
+ {
926
+ PyTuple pyargs ;
927
+ PyDict kwargs ;
928
+ GetArgs ( args , out pyargs , out kwargs ) ;
929
+ result = InvokeMethod ( binder . Name , pyargs , kwargs ) ;
930
+ return true ;
931
+ }
932
+ else
933
+ return base . TryInvokeMember ( binder , args , out result ) ;
866
934
}
867
935
936
+ public override bool TryInvoke ( InvokeBinder binder , object [ ] args , out object result )
937
+ {
938
+ if ( this . IsCallable ( ) )
939
+ {
940
+ PyTuple pyargs ;
941
+ PyDict kwargs ;
942
+ GetArgs ( args , out pyargs , out kwargs ) ;
943
+ result = Invoke ( pyargs , kwargs ) ;
944
+ return true ;
945
+ }
946
+ else
947
+ return base . TryInvoke ( binder , args , out result ) ;
948
+ }
949
+
950
+ public override bool TryConvert ( ConvertBinder binder , out object result )
951
+ {
952
+ return Converter . ToManaged ( this . obj , binder . Type , out result , false ) ;
953
+ }
868
954
955
+ public override bool TryBinaryOperation ( BinaryOperationBinder binder , Object arg , out Object result ) {
956
+ IntPtr res ;
957
+ if ( ! ( arg is PyObject ) )
958
+ arg = arg . ToPython ( ) ;
959
+
960
+ switch ( binder . Operation )
961
+ {
962
+ case ExpressionType . Add :
963
+ res = Runtime . PyNumber_Add ( this . obj , ( ( PyObject ) arg ) . obj ) ;
964
+ break ;
965
+ case ExpressionType . AddAssign :
966
+ res = Runtime . PyNumber_InPlaceAdd ( this . obj , ( ( PyObject ) arg ) . obj ) ;
967
+ break ;
968
+ case ExpressionType . Subtract :
969
+ res = Runtime . PyNumber_Subtract ( this . obj , ( ( PyObject ) arg ) . obj ) ;
970
+ break ;
971
+ case ExpressionType . SubtractAssign :
972
+ res = Runtime . PyNumber_InPlaceSubtract ( this . obj , ( ( PyObject ) arg ) . obj ) ;
973
+ break ;
974
+ case ExpressionType . Multiply :
975
+ res = Runtime . PyNumber_Multiply ( this . obj , ( ( PyObject ) arg ) . obj ) ;
976
+ break ;
977
+ case ExpressionType . MultiplyAssign :
978
+ res = Runtime . PyNumber_InPlaceMultiply ( this . obj , ( ( PyObject ) arg ) . obj ) ;
979
+ break ;
980
+ case ExpressionType . Divide :
981
+ res = Runtime . PyNumber_Divide ( this . obj , ( ( PyObject ) arg ) . obj ) ;
982
+ break ;
983
+ case ExpressionType . DivideAssign :
984
+ res = Runtime . PyNumber_InPlaceDivide ( this . obj , ( ( PyObject ) arg ) . obj ) ;
985
+ break ;
986
+ case ExpressionType . And :
987
+ res = Runtime . PyNumber_And ( this . obj , ( ( PyObject ) arg ) . obj ) ;
988
+ break ;
989
+ case ExpressionType . AndAssign :
990
+ res = Runtime . PyNumber_InPlaceAnd ( this . obj , ( ( PyObject ) arg ) . obj ) ;
991
+ break ;
992
+ case ExpressionType . ExclusiveOr :
993
+ res = Runtime . PyNumber_Xor ( this . obj , ( ( PyObject ) arg ) . obj ) ;
994
+ break ;
995
+ case ExpressionType . ExclusiveOrAssign :
996
+ res = Runtime . PyNumber_InPlaceXor ( this . obj , ( ( PyObject ) arg ) . obj ) ;
997
+ break ;
998
+ case ExpressionType . GreaterThan :
999
+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) > 0 ;
1000
+ return true ;
1001
+ case ExpressionType . GreaterThanOrEqual :
1002
+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) >= 0 ;
1003
+ return true ;
1004
+ case ExpressionType . LeftShift :
1005
+ res = Runtime . PyNumber_Lshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1006
+ break ;
1007
+ case ExpressionType . LeftShiftAssign :
1008
+ res = Runtime . PyNumber_InPlaceLshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1009
+ break ;
1010
+ case ExpressionType . LessThan :
1011
+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) < 0 ;
1012
+ return true ;
1013
+ case ExpressionType . LessThanOrEqual :
1014
+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) <= 0 ;
1015
+ return true ;
1016
+ case ExpressionType . Modulo :
1017
+ res = Runtime . PyNumber_Remainder ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1018
+ break ;
1019
+ case ExpressionType . ModuloAssign :
1020
+ res = Runtime . PyNumber_InPlaceRemainder ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1021
+ break ;
1022
+ case ExpressionType . NotEqual :
1023
+ result = Runtime . PyObject_Compare ( this . obj , ( ( PyObject ) arg ) . obj ) != 0 ;
1024
+ return true ;
1025
+ case ExpressionType . Or :
1026
+ res = Runtime . PyNumber_Or ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1027
+ break ;
1028
+ case ExpressionType . OrAssign :
1029
+ res = Runtime . PyNumber_InPlaceOr ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1030
+ break ;
1031
+ case ExpressionType . Power :
1032
+ res = Runtime . PyNumber_Power ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1033
+ break ;
1034
+ case ExpressionType . RightShift :
1035
+ res = Runtime . PyNumber_Rshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1036
+ break ;
1037
+ case ExpressionType . RightShiftAssign :
1038
+ res = Runtime . PyNumber_InPlaceRshift ( this . obj , ( ( PyObject ) arg ) . obj ) ;
1039
+ break ;
1040
+ default :
1041
+ result = null ;
1042
+ return false ;
1043
+ }
1044
+ result = new PyObject ( res ) ;
1045
+ return true ;
1046
+ }
1047
+
1048
+ public override bool TryUnaryOperation ( UnaryOperationBinder binder , out Object result )
1049
+ {
1050
+ int r ;
1051
+ IntPtr res ;
1052
+ switch ( binder . Operation )
1053
+ {
1054
+ case ExpressionType . Negate :
1055
+ res = Runtime . PyNumber_Negative ( this . obj ) ;
1056
+ break ;
1057
+ case ExpressionType . UnaryPlus :
1058
+ res = Runtime . PyNumber_Positive ( this . obj ) ;
1059
+ break ;
1060
+ case ExpressionType . OnesComplement :
1061
+ res = Runtime . PyNumber_Invert ( this . obj ) ;
1062
+ break ;
1063
+ case ExpressionType . Not :
1064
+ r = Runtime . PyObject_Not ( this . obj ) ;
1065
+ result = r == 1 ;
1066
+ return r != - 1 ;
1067
+ case ExpressionType . IsFalse :
1068
+ r = Runtime . PyObject_IsTrue ( this . obj ) ;
1069
+ result = r == 0 ;
1070
+ return r != - 1 ;
1071
+ case ExpressionType . IsTrue :
1072
+ r = Runtime . PyObject_IsTrue ( this . obj ) ;
1073
+ result = r == 1 ;
1074
+ return r != - 1 ;
1075
+ case ExpressionType . Decrement :
1076
+ case ExpressionType . Increment :
1077
+ default :
1078
+ result = null ;
1079
+ return false ;
1080
+ }
1081
+ result = new PyObject ( res ) ;
1082
+ return true ;
1083
+ }
1084
+ }
869
1085
}
0 commit comments