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
)
203 return check_type (from, to
.GetElementType ());
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
: 0;
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;