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;
54 internal static Binder DefaultBinder {
56 if (null == default_binder)
58 lock (typeof (Binder))
60 if (default_binder == null)
61 default_binder = new Default ();
63 return default_binder;
67 return default_binder;
71 internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
73 if ( pinfo.Length == 0)
76 throw new TargetParameterCountException ();
78 if (pinfo.Length != args.Length)
79 throw new TargetParameterCountException ();
80 for (int i = 0; i < args.Length; ++i) {
81 object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
82 if ((v == null) && (args [i] != null))
89 internal static int GetDerivedLevel (Type type)
91 Type searchType = type;
94 while (searchType.BaseType != null)
97 searchType = searchType.BaseType;
103 internal static MethodBase FindMostDerivedMatch (MethodBase [] match)
107 int count = match.Length;
109 for (int current = 0; current < count; current++)
111 int level = GetDerivedLevel (match[current].DeclaringType);
112 if (level == highLevel)
113 throw new AmbiguousMatchException ();
115 if (level > highLevel)
122 return match[matchId];
125 internal sealed class Default : Binder {
126 public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
129 throw new ArgumentNullException ("match");
130 foreach (FieldInfo f in match) {
131 if (check_type (value.GetType (), f.FieldType))
138 public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
142 types = Type.EmptyTypes;
144 types = new Type [args.Length];
145 for (int i = 0; i < args.Length; ++i) {
146 if (args [i] != null)
147 types [i] = args [i].GetType ();
150 MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
155 static bool IsArrayAssignable (Type object_type, Type target_type)
157 if (object_type.IsArray && target_type.IsArray)
158 return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
160 if (target_type.IsAssignableFrom (object_type))
166 public override object ChangeType (object value, Type type, CultureInfo culture)
170 Type vtype = value.GetType ();
172 type = type.GetElementType ();
173 if (vtype == type || type.IsAssignableFrom (vtype))
175 if (vtype.IsArray && type.IsArray){
176 if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
180 if (check_type (vtype, type))
181 return Convert.ChangeType (value, type);
186 public override void ReorderArgumentArray (ref object[] args, object state)
188 //do nothing until we support named arguments
189 //throw new NotImplementedException ();
192 private static bool check_type (Type from, Type to) {
197 return !to.IsValueType;
199 TypeCode fromt = Type.GetTypeCode (from);
200 TypeCode tot = Type.GetTypeCode (to);
202 if (to.IsByRef != from.IsByRef)
208 case TypeCode.UInt16:
209 case TypeCode.UInt32:
211 case TypeCode.UInt64:
213 case TypeCode.Single:
214 case TypeCode.Double:
217 return to == typeof (object);
221 case TypeCode.UInt16:
223 case TypeCode.UInt32:
225 case TypeCode.UInt64:
227 case TypeCode.Single:
228 case TypeCode.Double:
231 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
237 case TypeCode.Single:
238 case TypeCode.Double:
241 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
242 case TypeCode.UInt16:
244 case TypeCode.UInt32:
246 case TypeCode.UInt64:
248 case TypeCode.Single:
249 case TypeCode.Double:
252 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
257 case TypeCode.Single:
258 case TypeCode.Double:
261 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
262 case TypeCode.UInt32:
264 case TypeCode.UInt64:
266 case TypeCode.Single:
267 case TypeCode.Double:
270 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
274 case TypeCode.Single:
275 case TypeCode.Double:
278 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
279 case TypeCode.UInt64:
282 case TypeCode.Single:
283 case TypeCode.Double:
286 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
287 case TypeCode.Single:
288 return tot == TypeCode.Double || to == typeof (object);
290 /* TODO: handle valuetype -> byref */
291 if (to == typeof (object) && from.IsValueType)
294 return to.IsAssignableFrom (from);
298 private static bool check_arguments (Type[] types, ParameterInfo[] args) {
299 for (int i = 0; i < types.Length; ++i) {
300 if (!check_type (types [i], args [i].ParameterType))
306 public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
312 throw new ArgumentNullException ("match");
314 /* first look for an exact match... */
315 for (i = 0; i < match.Length; ++i) {
317 ParameterInfo[] args = m.GetParameters ();
318 if (args.Length != types.Length)
320 for (j = 0; j < types.Length; ++j) {
321 if (types [j] != args [j].ParameterType)
324 if (j == types.Length)
328 MethodBase result = null;
329 for (i = 0; i < match.Length; ++i) {
331 ParameterInfo[] args = m.GetParameters ();
332 if (args.Length != types.Length)
334 if (!check_arguments (types, args))
338 throw new AmbiguousMatchException ();
346 public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
348 if (match == null || match.Length == 0)
349 throw new ArgumentException ("No properties provided", "match");
351 bool haveRet = (returnType != null);
352 int idxlen = (indexes != null) ? indexes.Length : -1;
353 PropertyInfo result = null;
355 int best_score = Int32.MaxValue - 1;
356 int fail_score = Int32.MaxValue;
359 for (i = match.Length - 1; i >= 0; i--) {
360 PropertyInfo p = match [i];
361 ParameterInfo[] args = p.GetIndexParameters ();
362 if (idxlen >= 0 && idxlen != args.Length)
365 if (haveRet && !check_type (p.PropertyType, returnType))
368 int score = Int32.MaxValue - 1;
370 score = check_arguments_with_score (indexes, args);
375 int new_level = GetDerivedLevel (p.DeclaringType);
376 if (result != null) {
377 if (best_score < score)
380 if (best_score == score) {
381 if (level == new_level) {
382 // Keep searching. May be there's something
388 if (level > new_level)
398 if (fail_score <= best_score)
399 throw new AmbiguousMatchException ();
404 static int check_arguments_with_score (Type [] types, ParameterInfo [] args)
408 for (int i = 0; i < types.Length; ++i) {
409 int res = check_type_with_score (types [i], args [i].ParameterType);
420 // 0 -> same type or null and !valuetype
422 // 2 -> value type that don't lose data
423 // 3 -> to == IsAssignableFrom
425 static int check_type_with_score (Type from, Type to)
428 return to.IsValueType ? -1 : 0;
433 if (to == typeof (object))
436 TypeCode fromt = Type.GetTypeCode (from);
437 TypeCode tot = Type.GetTypeCode (to);
442 case TypeCode.UInt16:
445 case TypeCode.UInt32:
447 case TypeCode.UInt64:
449 case TypeCode.Single:
450 case TypeCode.Double:
457 case TypeCode.UInt16:
459 case TypeCode.UInt32:
461 case TypeCode.UInt64:
463 case TypeCode.Single:
464 case TypeCode.Double:
467 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
473 case TypeCode.Single:
474 case TypeCode.Double:
477 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
478 case TypeCode.UInt16:
480 case TypeCode.UInt32:
482 case TypeCode.UInt64:
484 case TypeCode.Single:
485 case TypeCode.Double:
488 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
493 case TypeCode.Single:
494 case TypeCode.Double:
497 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
498 case TypeCode.UInt32:
500 case TypeCode.UInt64:
502 case TypeCode.Single:
503 case TypeCode.Double:
506 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
510 case TypeCode.Single:
511 case TypeCode.Double:
514 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
515 case TypeCode.UInt64:
518 case TypeCode.Single:
519 case TypeCode.Double:
522 return (from.IsEnum && to == typeof (Enum)) ? 1 : -1;
523 case TypeCode.Single:
524 return tot == TypeCode.Double ? 2 : -1;
526 return (to.IsAssignableFrom (from)) ? 3 : -1;