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
40 [ClassInterface(ClassInterfaceType.AutoDual)]
41 public abstract class Binder
43 protected Binder () {}
45 public abstract FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture);
46 public abstract MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state);
47 public abstract object ChangeType (object value, Type type, CultureInfo culture);
48 public abstract void ReorderArgumentArray( ref object[] args, object state);
49 public abstract MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
50 public abstract PropertyInfo SelectProperty( BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
52 static Binder default_binder = new Default ();
54 internal static Binder DefaultBinder {
56 return default_binder;
60 internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
62 if ( pinfo.Length == 0)
65 throw new TargetParameterCountException ();
67 if (pinfo.Length != args.Length)
68 throw new TargetParameterCountException ();
69 for (int i = 0; i < args.Length; ++i) {
70 object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
71 if ((v == null) && (args [i] != null))
78 internal static int GetDerivedLevel (Type type)
80 Type searchType = type;
83 while (searchType.BaseType != null)
86 searchType = searchType.BaseType;
92 internal static MethodBase FindMostDerivedMatch (MethodBase [] match)
96 int count = match.Length;
98 for (int current = 0; current < count; current++)
100 int level = GetDerivedLevel (match[current].DeclaringType);
101 if (level == highLevel)
102 throw new AmbiguousMatchException ();
104 if (level > highLevel)
111 return match[matchId];
114 internal sealed class Default : Binder {
115 public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
118 throw new ArgumentNullException ("match");
119 foreach (FieldInfo f in match) {
120 if (check_type (value.GetType (), f.FieldType))
127 public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
131 types = Type.EmptyTypes;
133 types = new Type [args.Length];
134 for (int i = 0; i < args.Length; ++i) {
135 if (args [i] != null)
136 types [i] = args [i].GetType ();
139 MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
144 static bool IsArrayAssignable (Type object_type, Type target_type)
146 if (object_type.IsArray && target_type.IsArray)
147 return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
149 if (target_type.IsAssignableFrom (object_type))
155 public override object ChangeType (object value, Type type, CultureInfo culture)
159 Type vtype = value.GetType ();
161 type = type.GetElementType ();
162 if (vtype == type || type.IsInstanceOfType (value))
164 if (vtype.IsArray && type.IsArray){
165 if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
169 if (check_type (vtype, type))
170 return Convert.ChangeType (value, type);
175 public override void ReorderArgumentArray (ref object[] args, object state)
177 //do nothing until we support named arguments
178 //throw new NotImplementedException ();
181 private static bool check_type (Type from, Type to) {
186 return !to.IsValueType;
188 TypeCode fromt = Type.GetTypeCode (from);
189 TypeCode tot = Type.GetTypeCode (to);
191 if (to.IsByRef != from.IsByRef)
197 case TypeCode.UInt16:
198 case TypeCode.UInt32:
200 case TypeCode.UInt64:
202 case TypeCode.Single:
203 case TypeCode.Double:
206 return to == typeof (object);
210 case TypeCode.UInt16:
212 case TypeCode.UInt32:
214 case TypeCode.UInt64:
216 case TypeCode.Single:
217 case TypeCode.Double:
220 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
226 case TypeCode.Single:
227 case TypeCode.Double:
230 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
231 case TypeCode.UInt16:
233 case TypeCode.UInt32:
235 case TypeCode.UInt64:
237 case TypeCode.Single:
238 case TypeCode.Double:
241 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
246 case TypeCode.Single:
247 case TypeCode.Double:
250 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
251 case TypeCode.UInt32:
253 case TypeCode.UInt64:
255 case TypeCode.Single:
256 case TypeCode.Double:
259 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
263 case TypeCode.Single:
264 case TypeCode.Double:
267 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
268 case TypeCode.UInt64:
271 case TypeCode.Single:
272 case TypeCode.Double:
275 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
276 case TypeCode.Single:
277 return tot == TypeCode.Double || to == typeof (object);
279 /* TODO: handle valuetype -> byref */
280 if (to == typeof (object) && from.IsValueType)
283 return to.IsAssignableFrom (from);
287 private static bool check_arguments (Type[] types, ParameterInfo[] args) {
288 for (int i = 0; i < types.Length; ++i) {
289 if (!check_type (types [i], args [i].ParameterType))
295 public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
301 throw new ArgumentNullException ("match");
303 /* first look for an exact match... */
304 for (i = 0; i < match.Length; ++i) {
306 ParameterInfo[] args = m.GetParameters ();
307 if (args.Length != types.Length)
309 for (j = 0; j < types.Length; ++j) {
310 if (types [j] != args [j].ParameterType)
313 if (j == types.Length)
317 MethodBase result = null;
318 for (i = 0; i < match.Length; ++i) {
320 ParameterInfo[] args = m.GetParameters ();
321 if (args.Length != types.Length)
323 if (!check_arguments (types, args))
327 throw new AmbiguousMatchException ();
335 public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
337 if (match == null || match.Length == 0)
338 throw new ArgumentException ("No properties provided", "match");
340 bool haveRet = (returnType != null);
341 int idxlen = (indexes != null) ? indexes.Length : -1;
342 PropertyInfo result = null;
344 int best_score = Int32.MaxValue - 1;
345 int fail_score = Int32.MaxValue;
348 for (i = match.Length - 1; i >= 0; i--) {
349 PropertyInfo p = match [i];
350 ParameterInfo[] args = p.GetIndexParameters ();
351 if (idxlen >= 0 && idxlen != args.Length)
354 if (haveRet && !check_type (p.PropertyType, returnType))
357 int score = Int32.MaxValue - 1;
359 score = check_arguments_with_score (indexes, args);
364 int new_level = GetDerivedLevel (p.DeclaringType);
365 if (result != null) {
366 if (best_score < score)
369 if (best_score == score) {
370 if (level == new_level) {
371 // Keep searching. May be there's something
377 if (level > new_level)
387 if (fail_score <= best_score)
388 throw new AmbiguousMatchException ();
393 static int check_arguments_with_score (Type [] types, ParameterInfo [] args)
397 for (int i = 0; i < types.Length; ++i) {
398 int res = check_type_with_score (types [i], args [i].ParameterType);
409 // 0 -> same type or null and !valuetype
411 // 2 -> value type that don't lose data
412 // 3 -> to == IsAssignableFrom
414 static int check_type_with_score (Type from, Type to)
417 return to.IsValueType ? -1 : 0;
422 if (to == typeof (object))
425 TypeCode fromt = Type.GetTypeCode (from);
426 TypeCode tot = Type.GetTypeCode (to);
431 case TypeCode.UInt16:
434 case TypeCode.UInt32:
436 case TypeCode.UInt64:
438 case TypeCode.Single:
439 case TypeCode.Double:
446 case TypeCode.UInt16:
448 case TypeCode.UInt32:
450 case TypeCode.UInt64:
452 case TypeCode.Single:
453 case TypeCode.Double:
456 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
462 case TypeCode.Single:
463 case TypeCode.Double:
466 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
467 case TypeCode.UInt16:
469 case TypeCode.UInt32:
471 case TypeCode.UInt64:
473 case TypeCode.Single:
474 case TypeCode.Double:
477 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
482 case TypeCode.Single:
483 case TypeCode.Double:
486 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
487 case TypeCode.UInt32:
489 case TypeCode.UInt64:
491 case TypeCode.Single:
492 case TypeCode.Double:
495 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
499 case TypeCode.Single:
500 case TypeCode.Double:
503 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
504 case TypeCode.UInt64:
507 case TypeCode.Single:
508 case TypeCode.Double:
511 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
512 case TypeCode.Single:
513 return tot == TypeCode.Double ? 2 : -1;
515 return (to.IsAssignableFrom (from)) ? 3 : -1;