2 Copyright (C) 2010-2012 Jeroen Frijters
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.
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:
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.
25 using System.Globalization;
27 namespace IKVM.Reflection
29 public abstract class Binder
35 public virtual MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
37 throw new InvalidOperationException();
40 public virtual FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
42 throw new InvalidOperationException();
45 public virtual object ChangeType(object value, Type type, CultureInfo culture)
47 throw new InvalidOperationException();
50 public virtual void ReorderArgumentArray(ref object[] args, object state)
52 throw new InvalidOperationException();
55 public abstract MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
56 public abstract PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
59 sealed class DefaultBinder : Binder
61 public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
64 foreach (MethodBase method in match)
66 if (MatchParameterTypes(method.GetParameters(), types))
68 match[matchCount++] = method;
82 MethodBase bestMatch = match[0];
83 bool ambiguous = false;
84 for (int i = 1; i < matchCount; i++)
86 bestMatch = SelectBestMatch(bestMatch, match[i], types, ref ambiguous);
90 throw new AmbiguousMatchException();
95 private static bool MatchParameterTypes(ParameterInfo[] parameters, Type[] types)
97 if (parameters.Length != types.Length)
101 for (int i = 0; i < parameters.Length; i++)
103 Type sourceType = types[i];
104 Type targetType = parameters[i].ParameterType;
105 if (sourceType != targetType
106 && !targetType.IsAssignableFrom(sourceType)
107 && !IsAllowedPrimitiveConversion(sourceType, targetType))
115 private static MethodBase SelectBestMatch(MethodBase mb1, MethodBase mb2, Type[] types, ref bool ambiguous)
117 switch (MatchSignatures(mb1.MethodSignature, mb2.MethodSignature, types))
125 if (mb1.MethodSignature.MatchParameterTypes(mb2.MethodSignature))
127 int depth1 = GetInheritanceDepth(mb1.DeclaringType);
128 int depth2 = GetInheritanceDepth(mb2.DeclaringType);
133 else if (depth1 < depth2)
143 private static int GetInheritanceDepth(Type type)
149 type = type.BaseType;
154 private static int MatchSignatures(MethodSignature sig1, MethodSignature sig2, Type[] types)
156 for (int i = 0; i < sig1.GetParameterCount(); i++)
158 Type type1 = sig1.GetParameterType(i);
159 Type type2 = sig2.GetParameterType(i);
162 return MatchTypes(type1, type2, types[i]);
168 private static int MatchSignatures(PropertySignature sig1, PropertySignature sig2, Type[] types)
170 for (int i = 0; i < sig1.ParameterCount; i++)
172 Type type1 = sig1.GetParameter(i);
173 Type type2 = sig2.GetParameter(i);
176 return MatchTypes(type1, type2, types[i]);
182 private static int MatchTypes(Type type1, Type type2, Type type)
192 bool conv = type1.IsAssignableFrom(type2);
193 return conv == type2.IsAssignableFrom(type1) ? 0 : conv ? 2 : 1;
196 private static bool IsAllowedPrimitiveConversion(Type source, Type target)
198 // we need to check for primitives, because GetTypeCode will return the underlying type for enums
199 if (!source.IsPrimitive || !target.IsPrimitive)
203 TypeCode sourceType = Type.GetTypeCode(source);
204 TypeCode targetType = Type.GetTypeCode(target);
210 case TypeCode.UInt16:
211 case TypeCode.UInt32:
213 case TypeCode.UInt64:
215 case TypeCode.Single:
216 case TypeCode.Double:
225 case TypeCode.UInt16:
227 case TypeCode.UInt32:
229 case TypeCode.UInt64:
231 case TypeCode.Single:
232 case TypeCode.Double:
243 case TypeCode.Single:
244 case TypeCode.Double:
249 case TypeCode.UInt16:
252 case TypeCode.UInt32:
254 case TypeCode.UInt64:
256 case TypeCode.Single:
257 case TypeCode.Double:
267 case TypeCode.Single:
268 case TypeCode.Double:
273 case TypeCode.UInt32:
276 case TypeCode.UInt64:
278 case TypeCode.Single:
279 case TypeCode.Double:
288 case TypeCode.Single:
289 case TypeCode.Double:
294 case TypeCode.UInt64:
297 case TypeCode.Single:
298 case TypeCode.Double:
306 case TypeCode.Single:
307 case TypeCode.Double:
312 case TypeCode.Single:
315 case TypeCode.Double:
325 public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
328 foreach (PropertyInfo property in match)
330 if (indexes == null || MatchParameterTypes(property.GetIndexParameters(), indexes))
332 if (returnType != null)
334 if (property.PropertyType.IsPrimitive)
336 if (!IsAllowedPrimitiveConversion(returnType, property.PropertyType))
343 if (!property.PropertyType.IsAssignableFrom(returnType))
349 match[matchCount++] = property;
363 PropertyInfo bestMatch = match[0];
364 bool ambiguous = false;
365 for (int i = 1; i < matchCount; i++)
367 int best = MatchTypes(bestMatch.PropertyType, match[i].PropertyType, returnType);
368 if (best == 0 && indexes != null)
370 best = MatchSignatures(bestMatch.PropertySignature, match[i].PropertySignature, indexes);
374 int depth1 = GetInheritanceDepth(bestMatch.DeclaringType);
375 int depth2 = GetInheritanceDepth(match[i].DeclaringType);
376 if (bestMatch.Name == match[i].Name && depth1 != depth2)
395 bestMatch = match[i];
400 throw new AmbiguousMatchException();