IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
DefaultBinder.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2010-2012 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25
26namespace IKVM.Reflection
27{
28
29 sealed class DefaultBinder : Binder
30 {
31
32 public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
33 {
34 var matchCount = 0;
35 foreach (var method in match)
36 if (MatchParameterTypes(method.GetParameters(), types))
37 match[matchCount++] = method;
38
39 if (matchCount == 0)
40 return null;
41
42 var bestMatch = match[0];
43 var ambiguous = false;
44 for (int i = 1; i < matchCount; i++)
45 SelectBestMatch(match[i], types, ref bestMatch, ref ambiguous);
46
47 if (ambiguous)
48 throw new AmbiguousMatchException();
49
50 return bestMatch;
51 }
52
53 static bool MatchParameterTypes(ParameterInfo[] parameters, Type[] types)
54 {
55 if (parameters.Length != types.Length)
56 return false;
57
58 for (int i = 0; i < parameters.Length; i++)
59 {
60 var sourceType = types[i];
61 var targetType = parameters[i].ParameterType;
62 if (sourceType != targetType
63 && !targetType.IsAssignableFrom(sourceType)
64 && !IsAllowedPrimitiveConversion(sourceType, targetType))
65 return false;
66 }
67
68 return true;
69 }
70
71 static void SelectBestMatch(MethodBase candidate, Type[] types, ref MethodBase currentBest, ref bool ambiguous)
72 {
73 switch (MatchSignatures(currentBest, candidate, types))
74 {
75 case 1:
76 return;
77 case 2:
78 ambiguous = false;
79 currentBest = candidate;
80 return;
81 }
82
83 if (currentBest.MethodSignature.MatchParameterTypes(candidate.MethodSignature))
84 {
85 int depth1 = GetInheritanceDepth(currentBest.DeclaringType);
86 int depth2 = GetInheritanceDepth(candidate.DeclaringType);
87 if (depth1 > depth2)
88 {
89 return;
90 }
91 else if (depth1 < depth2)
92 {
93 ambiguous = false;
94 currentBest = candidate;
95 return;
96 }
97 }
98
99 ambiguous = true;
100 }
101
102 static int GetInheritanceDepth(Type type)
103 {
104 int depth = 0;
105 while (type != null)
106 {
107 depth++;
108 type = type.BaseType;
109 }
110 return depth;
111 }
112
113 static int MatchSignatures(MethodBase mb1, MethodBase mb2, Type[] types)
114 {
115 var sig1 = mb1.MethodSignature;
116 var sig2 = mb2.MethodSignature;
117 var gb1 = mb1 as IGenericBinder ?? mb1.DeclaringType;
118 var gb2 = mb2 as IGenericBinder ?? mb2.DeclaringType;
119 for (int i = 0; i < sig1.GetParameterCount(); i++)
120 {
121 var type1 = sig1.GetParameterType(gb1, i);
122 var type2 = sig2.GetParameterType(gb2, i);
123 if (type1 != type2)
124 return MatchTypes(type1, type2, types[i]);
125 }
126
127 return 0;
128 }
129
130 static int MatchSignatures(PropertySignature sig1, PropertySignature sig2, Type[] types)
131 {
132 for (int i = 0; i < sig1.ParameterCount; i++)
133 {
134 var type1 = sig1.GetParameter(i);
135 var type2 = sig2.GetParameter(i);
136 if (type1 != type2)
137 return MatchTypes(type1, type2, types[i]);
138 }
139
140 return 0;
141 }
142
143 static int MatchTypes(Type type1, Type type2, Type type)
144 {
145 if (type1 == type)
146 return 1;
147 if (type2 == type)
148 return 2;
149
150 var conv = type1.IsAssignableFrom(type2);
151 return conv == type2.IsAssignableFrom(type1) ? 0 : conv ? 2 : 1;
152 }
153
154 static bool IsAllowedPrimitiveConversion(Type source, Type target)
155 {
156 // we need to check for primitives, because GetTypeCode will return the underlying type for enums
157 if (!source.IsPrimitive || !target.IsPrimitive)
158 return false;
159
160 var sourceType = Type.GetTypeCode(source);
161 var targetType = Type.GetTypeCode(target);
162 switch (sourceType)
163 {
164 case TypeCode.Char:
165 switch (targetType)
166 {
167 case TypeCode.UInt16:
168 case TypeCode.UInt32:
169 case TypeCode.Int32:
170 case TypeCode.UInt64:
171 case TypeCode.Int64:
172 case TypeCode.Single:
173 case TypeCode.Double:
174 return true;
175 default:
176 return false;
177 }
178 case TypeCode.Byte:
179 switch (targetType)
180 {
181 case TypeCode.Char:
182 case TypeCode.UInt16:
183 case TypeCode.Int16:
184 case TypeCode.UInt32:
185 case TypeCode.Int32:
186 case TypeCode.UInt64:
187 case TypeCode.Int64:
188 case TypeCode.Single:
189 case TypeCode.Double:
190 return true;
191 default:
192 return false;
193 }
194 case TypeCode.SByte:
195 switch (targetType)
196 {
197 case TypeCode.Int16:
198 case TypeCode.Int32:
199 case TypeCode.Int64:
200 case TypeCode.Single:
201 case TypeCode.Double:
202 return true;
203 default:
204 return false;
205 }
206 case TypeCode.UInt16:
207 switch (targetType)
208 {
209 case TypeCode.UInt32:
210 case TypeCode.Int32:
211 case TypeCode.UInt64:
212 case TypeCode.Int64:
213 case TypeCode.Single:
214 case TypeCode.Double:
215 return true;
216 default:
217 return false;
218 }
219 case TypeCode.Int16:
220 switch (targetType)
221 {
222 case TypeCode.Int32:
223 case TypeCode.Int64:
224 case TypeCode.Single:
225 case TypeCode.Double:
226 return true;
227 default:
228 return false;
229 }
230 case TypeCode.UInt32:
231 switch (targetType)
232 {
233 case TypeCode.UInt64:
234 case TypeCode.Int64:
235 case TypeCode.Single:
236 case TypeCode.Double:
237 return true;
238 default:
239 return false;
240 }
241 case TypeCode.Int32:
242 switch (targetType)
243 {
244 case TypeCode.Int64:
245 case TypeCode.Single:
246 case TypeCode.Double:
247 return true;
248 default:
249 return false;
250 }
251 case TypeCode.UInt64:
252 switch (targetType)
253 {
254 case TypeCode.Single:
255 case TypeCode.Double:
256 return true;
257 default:
258 return false;
259 }
260 case TypeCode.Int64:
261 switch (targetType)
262 {
263 case TypeCode.Single:
264 case TypeCode.Double:
265 return true;
266 default:
267 return false;
268 }
269 case TypeCode.Single:
270 switch (targetType)
271 {
272 case TypeCode.Double:
273 return true;
274 default:
275 return false;
276 }
277 default:
278 return false;
279 }
280 }
281
282 public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
283 {
284 var matchCount = 0;
285
286 foreach (var property in match)
287 {
288 if (indexes == null || MatchParameterTypes(property.GetIndexParameters(), indexes))
289 {
290 if (returnType != null)
291 {
292 if (property.PropertyType.IsPrimitive)
293 {
294 if (!IsAllowedPrimitiveConversion(returnType, property.PropertyType))
295 continue;
296 }
297 else
298 {
299 if (!property.PropertyType.IsAssignableFrom(returnType))
300 continue;
301 }
302 }
303
304 match[matchCount++] = property;
305 }
306 }
307
308 if (matchCount == 0)
309 return null;
310
311 if (matchCount == 1)
312 return match[0];
313
314 var bestMatch = match[0];
315 var ambiguous = false;
316 for (int i = 1; i < matchCount; i++)
317 {
318 var best = MatchTypes(bestMatch.PropertyType, match[i].PropertyType, returnType);
319
320 if (best == 0 && indexes != null)
321 best = MatchSignatures(bestMatch.PropertySignature, match[i].PropertySignature, indexes);
322
323 if (best == 0)
324 {
325 var depth1 = GetInheritanceDepth(bestMatch.DeclaringType);
326 var depth2 = GetInheritanceDepth(match[i].DeclaringType);
327 if (bestMatch.Name == match[i].Name && depth1 != depth2)
328 {
329 if (depth1 > depth2)
330 best = 1;
331 else
332 best = 2;
333 }
334 else
335 {
336 ambiguous = true;
337 }
338 }
339
340 if (best == 2)
341 {
342 ambiguous = false;
343 bestMatch = match[i];
344 }
345 }
346
347 if (ambiguous)
348 throw new AmbiguousMatchException();
349
350 return bestMatch;
351 }
352
353 }
354
355}
IKVM.Reflection.Type Type
IKVM.Reflection.MethodBase MethodBase
override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)