1 // System.Reflection.Binder
3 // Sean MacIsaac (macisaac@ximian.com)
4 // Paolo Molaro (lupus@ximian.com)
6 // (C) Ximian, Inc. 2001 - 2002
8 using System.Globalization;
9 using System.Runtime.InteropServices;
11 namespace System.Reflection
14 [ClassInterface(ClassInterfaceType.AutoDual)]
15 public abstract class Binder
17 protected Binder () {}
19 public abstract FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture);
20 public abstract MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state);
21 public abstract object ChangeType (object value, Type type, CultureInfo culture);
22 public abstract void ReorderArgumentArray( ref object[] args, object state);
23 public abstract MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
24 public abstract PropertyInfo SelectProperty( BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
26 static Binder default_binder;
28 internal static Binder DefaultBinder {
30 if (null == default_binder)
32 lock (typeof (Binder))
\r
34 if (default_binder == null)
35 default_binder = new Default ();
37 return default_binder;
41 return default_binder;
45 internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
47 if ( pinfo.Length == 0)
50 throw new TargetParameterCountException ();
52 if (pinfo.Length != args.Length)
53 throw new TargetParameterCountException ();
54 for (int i = 0; i < args.Length; ++i) {
55 object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
56 if ((v == null) && (args [i] != null))
63 internal static int GetDerivedLevel (Type type)
\r
65 Type searchType = type;
\r
68 while (searchType.BaseType != null)
\r
71 searchType = searchType.BaseType;
\r
77 internal static MethodBase FindMostDerivedMatch (MethodBase [] match)
\r
81 int count = match.Length;
\r
83 for (int current = 0; current < count; current++)
\r
85 int level = GetDerivedLevel (match[current].DeclaringType);
\r
86 if (level == highLevel)
\r
87 throw new AmbiguousMatchException ();
\r
89 if (level > highLevel)
\r
96 return match[matchId];
\r
99 internal sealed class Default : Binder {
100 public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
103 throw new ArgumentNullException ("match");
104 foreach (FieldInfo f in match) {
105 if (check_type (value.GetType (), f.FieldType))
112 public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
116 types = Type.EmptyTypes;
118 types = new Type [args.Length];
119 for (int i = 0; i < args.Length; ++i) {
120 if (args [i] != null)
121 types [i] = args [i].GetType ();
124 MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
129 static bool IsArrayAssignable (Type object_type, Type target_type)
131 if (object_type.IsArray && target_type.IsArray)
132 return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
134 if (target_type.IsAssignableFrom (object_type))
140 public override object ChangeType (object value, Type type, CultureInfo culture)
144 Type vtype = value.GetType ();
145 if (vtype == type || type.IsAssignableFrom (vtype))
147 if (vtype.IsArray && type.IsArray){
148 if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
152 if (check_type (vtype, type))
153 return Convert.ChangeType (value, type);
158 public override void ReorderArgumentArray (ref object[] args, object state)
160 //do nothing until we support named arguments
161 //throw new NotImplementedException ();
164 private static bool check_type (Type from, Type to) {
167 TypeCode fromt = Type.GetTypeCode (from);
168 TypeCode tot = Type.GetTypeCode (to);
173 case TypeCode.UInt16:
174 case TypeCode.UInt32:
176 case TypeCode.UInt64:
178 case TypeCode.Single:
179 case TypeCode.Double:
182 return to == typeof (object);
186 case TypeCode.UInt16:
188 case TypeCode.UInt32:
190 case TypeCode.UInt64:
192 case TypeCode.Single:
193 case TypeCode.Double:
196 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
202 case TypeCode.Single:
203 case TypeCode.Double:
206 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
207 case TypeCode.UInt16:
209 case TypeCode.UInt32:
211 case TypeCode.UInt64:
213 case TypeCode.Single:
214 case TypeCode.Double:
217 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
222 case TypeCode.Single:
223 case TypeCode.Double:
226 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
227 case TypeCode.UInt32:
229 case TypeCode.UInt64:
231 case TypeCode.Single:
232 case TypeCode.Double:
235 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
239 case TypeCode.Single:
240 case TypeCode.Double:
243 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
244 case TypeCode.UInt64:
247 case TypeCode.Single:
248 case TypeCode.Double:
251 return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
252 case TypeCode.Single:
253 return tot == TypeCode.Double || to == typeof (object);
255 /* TODO: handle valuetype -> byref */
256 if (to == typeof (object) && from.IsValueType)
259 return to.IsAssignableFrom (from);
263 private static bool check_arguments (Type[] types, ParameterInfo[] args) {
264 for (int i = 0; i < types.Length; ++i) {
265 if (!check_type (types [i], args [i].ParameterType))
271 public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
276 throw new ArgumentNullException ("match");
277 /* first look for an exact match... */
278 for (i = 0; i < match.Length; ++i) {
280 ParameterInfo[] args = m.GetParameters ();
281 if (args.Length != types.Length)
283 for (j = 0; j < types.Length; ++j) {
284 if (types [j] != args [j].ParameterType)
287 if (j == types.Length)
290 for (i = 0; i < match.Length; ++i) {
292 ParameterInfo[] args = m.GetParameters ();
293 if (args.Length != types.Length)
295 if (!check_arguments (types, args))
302 public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
305 throw new ArgumentNullException ("match");
307 bool haveRet = (returnType != null);
308 foreach (PropertyInfo m in match) {
309 ParameterInfo[] args = m.GetIndexParameters ();
310 if (args.Length != indexes.Length)
313 if (haveRet && !check_type (m.PropertyType, returnType))
316 if (!check_arguments (indexes, args))