@@ -37,11 +37,11 @@ private CollectionRank GetRank(PyObject objectType)
37
37
return CollectionRank . Iterable ;
38
38
}
39
39
40
- private CollectionRank GetRank ( Type targetType )
40
+ private Tuple < CollectionRank , Type > GetRankAndType ( Type collectionType )
41
41
{
42
42
//if it is a plain IEnumerable, we can decode it using sequence protocol.
43
- if ( targetType == typeof ( System . Collections . IEnumerable ) )
44
- return CollectionRank . Iterable ;
43
+ if ( collectionType == typeof ( System . Collections . IEnumerable ) )
44
+ return new Tuple < CollectionRank , Type > ( CollectionRank . Iterable , typeof ( object ) ) ;
45
45
46
46
Func < Type , CollectionRank > getRankOfType = ( Type type ) => {
47
47
if ( type . GetGenericTypeDefinition ( ) == typeof ( IList < > ) )
@@ -53,32 +53,25 @@ private CollectionRank GetRank(Type targetType)
53
53
return CollectionRank . None ;
54
54
} ;
55
55
56
- if ( targetType . IsGenericType )
57
- {
58
- var thisRank = getRankOfType ( targetType ) ;
59
- if ( thisRank != CollectionRank . None )
60
- return thisRank ;
61
- }
62
-
63
- var maxRank = CollectionRank . None ;
64
- //if it implements any of the standard C# collection interfaces, we can decode it.
65
- foreach ( Type itf in targetType . GetInterfaces ( ) )
56
+ if ( collectionType . IsGenericType )
66
57
{
67
- if ( ! itf . IsGenericType ) continue ;
68
-
69
- var thisRank = getRankOfType ( itf ) ;
58
+ //for compatibility we *could* do this and copy the value but probably not the best option.
59
+ /*if (collectionType.GetGenericTypeDefinition() == typeof(List<>))
60
+ return new Tuple<CollectionRank, Type>(CollectionRank.List, elementType);*/
70
61
71
- //this is the most specialized type. return early
72
- if ( thisRank == CollectionRank . List ) return thisRank ;
73
-
74
- //if it is more specialized, assign to max rank
75
- if ( ( int ) thisRank > ( int ) maxRank )
76
- maxRank = thisRank ;
62
+ var elementType = collectionType . GetGenericArguments ( ) [ 0 ] ;
63
+ var thisRank = getRankOfType ( collectionType ) ;
64
+ if ( thisRank != CollectionRank . None )
65
+ return new Tuple < CollectionRank , Type > ( thisRank , elementType ) ;
77
66
}
78
67
79
- return maxRank ;
68
+ return null ;
80
69
}
81
70
71
+ private CollectionRank ? GetRank ( Type targetType )
72
+ {
73
+ return GetRankAndType ( targetType ) ? . Item1 ;
74
+ }
82
75
83
76
public bool CanDecode ( PyObject objectType , Type targetType )
84
77
{
@@ -89,7 +82,7 @@ public bool CanDecode(PyObject objectType, Type targetType)
89
82
90
83
//get the clr object rank
91
84
var clrRank = GetRank ( targetType ) ;
92
- if ( clrRank == CollectionRank . None )
85
+ if ( clrRank == null || clrRank == CollectionRank . None )
93
86
return false ;
94
87
95
88
//if it is a plain IEnumerable, we can decode it using sequence protocol.
@@ -99,15 +92,16 @@ public bool CanDecode(PyObject objectType, Type targetType)
99
92
return ( int ) pyRank >= ( int ) clrRank ;
100
93
}
101
94
102
- private class PyEnumerable : System . Collections . IEnumerable
95
+ private class GenericPyEnumerable < T > : IEnumerable < T >
103
96
{
104
- PyObject iterObject ;
105
- internal PyEnumerable ( PyObject pyObj )
97
+ protected PyObject iterObject ;
98
+
99
+ internal GenericPyEnumerable ( PyObject pyObj )
106
100
{
107
101
iterObject = new PyObject ( Runtime . PyObject_GetIter ( pyObj . Handle ) ) ;
108
102
}
109
103
110
- public IEnumerator GetEnumerator ( )
104
+ IEnumerator IEnumerable . GetEnumerator ( )
111
105
{
112
106
IntPtr item ;
113
107
while ( ( item = Runtime . PyIter_Next ( iterObject . Handle ) ) != IntPtr . Zero )
@@ -123,11 +117,32 @@ public IEnumerator GetEnumerator()
123
117
yield return obj ;
124
118
}
125
119
}
120
+
121
+ public IEnumerator < T > GetEnumerator ( )
122
+ {
123
+ IntPtr item ;
124
+ while ( ( item = Runtime . PyIter_Next ( iterObject . Handle ) ) != IntPtr . Zero )
125
+ {
126
+ object obj = null ;
127
+ if ( ! Converter . ToManaged ( item , typeof ( T ) , out obj , true ) )
128
+ {
129
+ Runtime . XDecref ( item ) ;
130
+ break ;
131
+ }
132
+
133
+ Runtime . XDecref ( item ) ;
134
+ yield return ( T ) obj ;
135
+ }
136
+ }
126
137
}
127
138
128
139
private object ToPlainEnumerable ( PyObject pyObj )
129
140
{
130
- return new PyEnumerable ( pyObj ) ;
141
+ return new GenericPyEnumerable < object > ( pyObj ) ;
142
+ }
143
+ private object ToEnumerable < T > ( PyObject pyObj )
144
+ {
145
+ return new GenericPyEnumerable < T > ( pyObj ) ;
131
146
}
132
147
133
148
public bool TryDecode < T > ( PyObject pyObj , out T value )
@@ -136,7 +151,16 @@ public bool TryDecode<T>(PyObject pyObj, out T value)
136
151
//first see if T is a plan IEnumerable
137
152
if ( typeof ( T ) == typeof ( System . Collections . IEnumerable ) )
138
153
{
139
- var = ToPlainEnumerable ( pyObj ) ;
154
+ var = new GenericPyEnumerable < object > ( pyObj ) ;
155
+ }
156
+
157
+ //next use the rank to return the appropriate type
158
+ var clrRank = GetRank ( typeof ( T ) ) ;
159
+ if ( clrRank == CollectionRank . Iterable )
160
+ var = new GenericPyEnumerable < int > ( pyObj ) ;
161
+ else
162
+ {
163
+ //var = null;
140
164
}
141
165
142
166
value = ( T ) var ;
0 commit comments