1 // System.Reflection.Binder
4 // Sean MacIsaac (macisaac@ximian.com)
5 // Paolo Molaro (lupus@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) Ximian, Inc. 2001 - 2003
9 // (c) Copyright 2004 Novell, Inc. (http://www.novell.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Globalization;
35 using System.Runtime.InteropServices;
37 namespace System.Reflection
43 [ClassInterface(ClassInterfaceType.AutoDual)]
44 public abstract class Binder
46 protected Binder () {}
48 public abstract FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture);
49 public abstract MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state);
50 public abstract object ChangeType (object value, Type type, CultureInfo culture);
51 public abstract void ReorderArgumentArray( ref object[] args, object state);
52 public abstract MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
53 public abstract PropertyInfo SelectProperty( BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
55 static Binder default_binder = new Default ();
57 internal static Binder DefaultBinder {
59 return default_binder;
63 internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
65 if ( pinfo.Length == 0)
68 throw new TargetParameterCountException ();
70 if (pinfo.Length != args.Length)
71 throw new TargetParameterCountException ();
72 for (int i = 0; i < args.Length; ++i) {
73 object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
74 if ((v == null) && (args [i] != null))
81 internal static int GetDerivedLevel (Type type)
83 Type searchType = type;
86 while (searchType.BaseType != null)
89 searchType = searchType.BaseType;
95 internal static MethodBase FindMostDerivedMatch (MethodBase [] match)
99 int count = match.Length;
101 for (int current = 0; current < count; current++)
103 int level = GetDerivedLevel (match[current].DeclaringType);
104 if (level == highLevel)
105 throw new AmbiguousMatchException ();
107 if (level > highLevel)
114 return match[matchId];
117 internal sealed class Default : Binder {
118 public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
121 throw new ArgumentNullException ("match");
122 foreach (FieldInfo f in match) {
123 if (check_type (value.GetType (), f.FieldType))
130 public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
134 types = Type.EmptyTypes;
136 types = new Type [args.Length];
137 for (int i = 0; i < args.Length; ++i) {
138 if (args [i] != null)
139 types [i] = args [i].GetType ();
142 MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
147 static bool IsArrayAssignable (Type object_type, Type target_type)
149 if (object_type.IsArray && target_type.IsArray)
150 return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
152 if (target_type.IsAssignableFrom (object_type))
158 public override object ChangeType (object value, Type type, CultureInfo culture)
162 Type vtype = value.GetType ();
164 type = type.GetElementType ();
165 if (vtype == type || type.IsInstanceOfType (value))
167 if (vtype.IsArray && type.IsArray){
168 if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
172 if (check_type (vtype, type))
173 return Convert.ChangeType (value, type);
178 public override void ReorderArgumentArray (ref object[] args, object state)
180 //do nothing until we support named arguments
181 //throw new NotImplementedException ();
184 private static bool check_type (Type from, Type to) {
191 TypeCode fromt = Type.GetTypeCode (from);
192 TypeCode tot = Type.GetTypeCode (to);
194 if (to.IsByRef != from.IsByRef)
200 case TypeCode.UInt16:
201 case TypeCode.UInt32:
203 case TypeCode.UInt64:
205 case TypeCode.Single:
206 case TypeCode.Double:
209 return to == typeof (object);
213 case TypeCode.UInt16:
215 case TypeCode.UInt32:
217 case TypeCode.UInt64:
219 case TypeCode.Single:
220 case TypeCode.Double:
223 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
229 case TypeCode.Single:
230 case TypeCode.Double:
233 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
234 case TypeCode.UInt16:
236 case TypeCode.UInt32:
238 case TypeCode.UInt64:
240 case TypeCode.Single:
241 case TypeCode.Double:
244 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
249 case TypeCode.Single:
250 case TypeCode.Double:
253 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
254 case TypeCode.UInt32:
256 case TypeCode.UInt64:
258 case TypeCode.Single:
259 case TypeCode.Double:
262 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
266 case TypeCode.Single:
267 case TypeCode.Double:
270 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
271 case TypeCode.UInt64:
274 case TypeCode.Single:
275 case TypeCode.Double:
278 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
279 case TypeCode.Single:
280 return tot == TypeCode.Double || to == typeof (object);
282 /* TODO: handle valuetype -> byref */
283 if (to == typeof (object) && from.IsValueType)
286 return to.IsAssignableFrom (from);
290 private static bool check_arguments (Type[] types, ParameterInfo[] args) {
291 for (int i = 0; i < types.Length; ++i) {
292 if (!check_type (types [i], args [i].ParameterType))
298 public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
304 throw new ArgumentNullException ("match");
306 /* first look for an exact match... */
307 for (i = 0; i < match.Length; ++i) {
309 ParameterInfo[] args = m.GetParameters ();
310 if (args.Length != types.Length)
312 for (j = 0; j < types.Length; ++j) {
313 if (types [j] != args [j].ParameterType)
316 if (j == types.Length)
320 MethodBase result = null;
321 for (i = 0; i < match.Length; ++i) {
323 ParameterInfo[] args = m.GetParameters ();
324 if (args.Length != types.Length)
326 if (!check_arguments (types, args))
330 throw new AmbiguousMatchException ();
338 public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
340 if (match == null || match.Length == 0)
341 throw new ArgumentException ("No properties provided", "match");
343 bool haveRet = (returnType != null);
344 int idxlen = (indexes != null) ? indexes.Length : -1;
345 PropertyInfo result = null;
347 int best_score = Int32.MaxValue - 1;
348 int fail_score = Int32.MaxValue;
351 for (i = match.Length - 1; i >= 0; i--) {
352 PropertyInfo p = match [i];
353 ParameterInfo[] args = p.GetIndexParameters ();
354 if (idxlen >= 0 && idxlen != args.Length)
357 if (haveRet && !check_type (p.PropertyType, returnType))
360 int score = Int32.MaxValue - 1;
362 score = check_arguments_with_score (indexes, args);
367 int new_level = GetDerivedLevel (p.DeclaringType);
368 if (result != null) {
369 if (best_score < score)
372 if (best_score == score) {
373 if (level == new_level) {
374 // Keep searching. May be there's something
380 if (level > new_level)
390 if (fail_score <= best_score)
391 throw new AmbiguousMatchException ();
396 static int check_arguments_with_score (Type [] types, ParameterInfo [] args)
400 for (int i = 0; i < types.Length; ++i) {
401 int res = check_type_with_score (types [i], args [i].ParameterType);
412 // 0 -> same type or null and !valuetype
414 // 2 -> value type that don't lose data
415 // 3 -> to == IsAssignableFrom
417 static int check_type_with_score (Type from, Type to)
420 return to.IsValueType ? -1 : 0;
425 if (to == typeof (object))
428 TypeCode fromt = Type.GetTypeCode (from);
429 TypeCode tot = Type.GetTypeCode (to);
434 case TypeCode.UInt16:
437 case TypeCode.UInt32:
439 case TypeCode.UInt64:
441 case TypeCode.Single:
442 case TypeCode.Double:
449 case TypeCode.UInt16:
451 case TypeCode.UInt32:
453 case TypeCode.UInt64:
455 case TypeCode.Single:
456 case TypeCode.Double:
459 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
465 case TypeCode.Single:
466 case TypeCode.Double:
469 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
470 case TypeCode.UInt16:
472 case TypeCode.UInt32:
474 case TypeCode.UInt64:
476 case TypeCode.Single:
477 case TypeCode.Double:
480 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
485 case TypeCode.Single:
486 case TypeCode.Double:
489 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
490 case TypeCode.UInt32:
492 case TypeCode.UInt64:
494 case TypeCode.Single:
495 case TypeCode.Double:
498 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
502 case TypeCode.Single:
503 case TypeCode.Double:
506 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
507 case TypeCode.UInt64:
510 case TypeCode.Single:
511 case TypeCode.Double:
514 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
515 case TypeCode.Single:
516 return tot == TypeCode.Double ? 2 : -1;
518 return (to.IsAssignableFrom (from)) ? 3 : -1;