Skip to content

Commit 074d01e

Browse files
committed
Changes DictionaryObject to KeyValuePairEnumerableObject
It is more generical. Verifies the existence of `Count` and `ContainsKey` that are necessary for `__len__` and `__contains__`.
1 parent 755d867 commit 074d01e

File tree

3 files changed

+31
-37
lines changed

3 files changed

+31
-37
lines changed

src/runtime/Python.Runtime.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
<Reference Include="System" />
7777
</ItemGroup>
7878
<ItemGroup>
79-
<Compile Include="dictionaryobject.cs" />
79+
<Compile Include="keyvaluepairenumerableobject.cs" />
8080
<Compile Include="finalizer.cs" />
8181
<Compile Include="Properties\AssemblyInfo.cs" />
8282
<Compile Include="..\SharedAssemblyInfo.cs">

src/runtime/classmanager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ private static ClassBase CreateClass(Type type)
8787
impl = new ArrayObject(type);
8888
}
8989

90-
else if (type.IsDictionary())
90+
else if (type.IsKeyValuePairEnumerable())
9191
{
92-
impl = new DictionaryObject(type);
92+
impl = new KeyValuePairEnumerableObject(type);
9393
}
9494

9595
else if (type.IsInterface)

src/runtime/dictionaryobject.cs renamed to src/runtime/keyvaluepairenumerableobject.cs

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
namespace Python.Runtime
66
{
77
/// <summary>
8-
/// Implements a Python type for managed dictionaries. This type is essentially
9-
/// the same as a ClassObject, except that it provides sequence semantics
10-
/// to support natural dictionary usage (__contains__ and __len__) from Python.
8+
/// Implements a Python type for managed KeyValuePairEnumerable (dictionaries).
9+
/// This type is essentially the same as a ClassObject, except that it provides
10+
/// sequence semantics to support natural dictionary usage (__contains__ and __len__)
11+
/// from Python.
1112
/// </summary>
12-
internal class DictionaryObject : ClassObject
13+
internal class KeyValuePairEnumerableObject : ClassObject
1314
{
1415
private static Dictionary<Tuple<Type, string>, MethodInfo> methodsByType = new Dictionary<Tuple<Type, string>, MethodInfo>();
1516
private static Dictionary<string, string> methodMap = new Dictionary<string, string>
@@ -20,11 +21,11 @@ internal class DictionaryObject : ClassObject
2021

2122
public List<string> MappedMethods { get; } = new List<string>();
2223

23-
internal DictionaryObject(Type tp) : base(tp)
24+
internal KeyValuePairEnumerableObject(Type tp) : base(tp)
2425
{
25-
if (!tp.IsDictionary())
26+
if (!tp.IsKeyValuePairEnumerable())
2627
{
27-
throw new ArgumentException("object is not a dict");
28+
throw new ArgumentException("object is not a KeyValuePair Enumerable");
2829
}
2930

3031
foreach (var name in methodMap)
@@ -59,11 +60,8 @@ public static int mp_length(IntPtr ob)
5960
var obj = (CLRObject)GetManagedObject(ob);
6061
var self = obj.inst;
6162

62-
MethodInfo methodInfo;
63-
if (!TryGetMethodInfo(self.GetType(), "Count", out methodInfo))
64-
{
65-
return 0;
66-
}
63+
var key = Tuple.Create(self.GetType(), "Count");
64+
var methodInfo = methodsByType[key];
6765

6866
return (int)methodInfo.Invoke(self, null);
6967
}
@@ -76,11 +74,8 @@ public static int sq_contains(IntPtr ob, IntPtr v)
7674
var obj = (CLRObject)GetManagedObject(ob);
7775
var self = obj.inst;
7876

79-
MethodInfo methodInfo;
80-
if (!TryGetMethodInfo(self.GetType(), "ContainsKey", out methodInfo))
81-
{
82-
return 0;
83-
}
77+
var key = Tuple.Create(self.GetType(), "ContainsKey");
78+
var methodInfo = methodsByType[key];
8479

8580
var parameters = methodInfo.GetParameters();
8681
object arg;
@@ -92,29 +87,15 @@ public static int sq_contains(IntPtr ob, IntPtr v)
9287

9388
return (bool)methodInfo.Invoke(self, new[] { arg }) ? 1 : 0;
9489
}
95-
96-
private static bool TryGetMethodInfo(Type type, string alias, out MethodInfo methodInfo)
97-
{
98-
var key = Tuple.Create(type, alias);
99-
100-
if (!methodsByType.TryGetValue(key, out methodInfo))
101-
{
102-
Exceptions.SetError(Exceptions.TypeError,
103-
$"{nameof(type)} does not define {alias} method");
104-
105-
return false;
106-
}
107-
108-
return true;
109-
}
11090
}
11191

112-
public static class DictionaryObjectExtension
92+
public static class KeyValuePairEnumerableObjectExtension
11393
{
114-
public static bool IsDictionary(this Type type)
94+
public static bool IsKeyValuePairEnumerable(this Type type)
11595
{
11696
var iEnumerableType = typeof(IEnumerable<>);
11797
var keyValuePairType = typeof(KeyValuePair<,>);
98+
var requiredMethods = new[] { "ContainsKey", "Count" };
11899

119100
var interfaces = type.GetInterfaces();
120101
foreach (var i in interfaces)
@@ -130,6 +111,19 @@ public static bool IsDictionary(this Type type)
130111
a.GetGenericTypeDefinition() == keyValuePairType &&
131112
a.GetGenericArguments().Length == 2)
132113
{
114+
foreach (var requiredMethod in requiredMethods)
115+
{
116+
var method = type.GetMethod(requiredMethod);
117+
if (method == null)
118+
{
119+
method = type.GetMethod($"get_{requiredMethod}");
120+
if (method == null)
121+
{
122+
return false;
123+
}
124+
}
125+
}
126+
133127
return true;
134128
}
135129
}

0 commit comments

Comments
 (0)