2003-11-11 Todd Berman <tberman@gentoo.org>
[mono.git] / mcs / class / corlib / System.Reflection / Binder.cs
1 // System.Reflection.Binder
2 //
3 // Sean MacIsaac (macisaac@ximian.com)
4 // Paolo Molaro (lupus@ximian.com)
5 //
6 // (C) Ximian, Inc. 2001 - 2002
7
8 using System.Globalization;
9
10 namespace System.Reflection
11 {
12         [Serializable]
13         public abstract class Binder
14         {
15                 protected Binder () {}
16
17                 public abstract FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture);
18                 public abstract MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state);
19                 public abstract object ChangeType (object value, Type type, CultureInfo culture);
20                 public abstract void ReorderArgumentArray( ref object[] args, object state);
21                 public abstract MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers);
22                 public abstract PropertyInfo SelectProperty( BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers);
23
24                 static Binder default_binder;
25
26                 internal static Binder DefaultBinder {
27                         get {
28                                 if (null == default_binder)
29                                 {
30                                         lock (typeof (Binder)) \r
31                                         {
32                                                 if (default_binder == null)
33                                                         default_binder = new Default ();
34
35                                                 return default_binder;
36                                         }
37                                 }
38
39                                 return default_binder;
40                         }
41                 }
42                 
43                 internal static bool ConvertArgs (Binder binder, object[] args, ParameterInfo[] pinfo, CultureInfo culture) {
44                         if (args == null) {
45                                 if ( pinfo.Length == 0)
46                                         return true;
47                                 else
48                                         throw new TargetParameterCountException ();
49                         }
50                         if (pinfo.Length != args.Length)
51                                 throw new TargetParameterCountException ();
52                         for (int i = 0; i < args.Length; ++i) {
53                                 object v = binder.ChangeType (args [i], pinfo[i].ParameterType, culture);
54                                 if ((v == null) && (args [i] != null))
55                                         return false;
56                                 args [i] = v;
57                         }
58                         return true;
59                 }
60
61                 internal sealed class Default : Binder {
62                         public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) 
63                         {
64                                 if (match == null)
65                                         throw new ArgumentNullException ("match");
66                                 foreach (FieldInfo f in match) {
67                                         if (check_type (value.GetType (), f.FieldType))
68                                                 return f;
69                                 }
70                                 return null;
71                         }
72
73                         [MonoTODO]
74                         public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
75                         {
76                                 Type[] types;
77                                 if (args == null)
78                                         types = Type.EmptyTypes;
79                                 else {
80                                         types = new Type [args.Length];
81                                         for (int i = 0; i < args.Length; ++i) {
82                                                 if (args [i] != null)
83                                                         types [i] = args [i].GetType ();
84                                         }
85                                 }
86                                 MethodBase selected = SelectMethod (bindingAttr, match, types, modifiers);
87                                 state = null;
88                                 return selected;
89                         }
90
91                         static bool IsArrayAssignable (Type object_type, Type target_type)
92                         {
93                                 if (object_type.IsArray && target_type.IsArray)
94                                         return IsArrayAssignable (object_type.GetElementType (), target_type.GetElementType ());
95                                                 
96                                 if (target_type.IsAssignableFrom (object_type))
97                                         return true;
98
99                                 return false;
100                         }
101                         
102                         public override object ChangeType (object value, Type type, CultureInfo culture)
103                         {
104                                 if (value == null)
105                                         return null;
106                                 Type vtype = value.GetType ();
107                                 if (vtype == type || type.IsAssignableFrom (vtype))
108                                         return value;
109                                 if (vtype.IsArray && type.IsArray){
110                                         if (IsArrayAssignable (vtype.GetElementType (), type.GetElementType ()))
111                                                 return value;
112                                 }
113
114                                 if (check_type (vtype, type))
115                                         return Convert.ChangeType (value, type);
116                                 return null;
117                         }
118
119                         [MonoTODO]
120                         public override void ReorderArgumentArray (ref object[] args, object state)
121                         {
122                                 //do nothing until we support named arguments
123                                 //throw new NotImplementedException ();
124                         }
125
126                         private static bool check_type (Type from, Type to) {
127                                 if (from == to)
128                                         return true;
129                                 TypeCode fromt = Type.GetTypeCode (from);
130                                 TypeCode tot = Type.GetTypeCode (to);
131
132                                 switch (fromt) {
133                                 case TypeCode.Char:
134                                         switch (tot) {
135                                         case TypeCode.UInt16:
136                                         case TypeCode.UInt32:
137                                         case TypeCode.Int32:
138                                         case TypeCode.UInt64:
139                                         case TypeCode.Int64:
140                                         case TypeCode.Single:
141                                         case TypeCode.Double:
142                                                 return true;
143                                         }
144                                         return to == typeof (object);
145                                 case TypeCode.Byte:
146                                         switch (tot) {
147                                         case TypeCode.Char:
148                                         case TypeCode.UInt16:
149                                         case TypeCode.Int16:
150                                         case TypeCode.UInt32:
151                                         case TypeCode.Int32:
152                                         case TypeCode.UInt64:
153                                         case TypeCode.Int64:
154                                         case TypeCode.Single:
155                                         case TypeCode.Double:
156                                                 return true;
157                                         }
158                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
159                                 case TypeCode.SByte:
160                                         switch (tot) {
161                                         case TypeCode.Int16:
162                                         case TypeCode.Int32:
163                                         case TypeCode.Int64:
164                                         case TypeCode.Single:
165                                         case TypeCode.Double:
166                                                 return true;
167                                         }
168                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
169                                 case TypeCode.UInt16:
170                                         switch (tot) {
171                                         case TypeCode.UInt32:
172                                         case TypeCode.Int32:
173                                         case TypeCode.UInt64:
174                                         case TypeCode.Int64:
175                                         case TypeCode.Single:
176                                         case TypeCode.Double:
177                                                 return true;
178                                         }
179                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
180                                 case TypeCode.Int16:
181                                         switch (tot) {
182                                         case TypeCode.Int32:
183                                         case TypeCode.Int64:
184                                         case TypeCode.Single:
185                                         case TypeCode.Double:
186                                                 return true;
187                                         }
188                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
189                                 case TypeCode.UInt32:
190                                         switch (tot) {
191                                         case TypeCode.UInt64:
192                                         case TypeCode.Int64:
193                                         case TypeCode.Single:
194                                         case TypeCode.Double:
195                                                 return true;
196                                         }
197                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
198                                 case TypeCode.Int32:
199                                         switch (tot) {
200                                         case TypeCode.Int64:
201                                         case TypeCode.Single:
202                                         case TypeCode.Double:
203                                                 return true;
204                                         }
205                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
206                                 case TypeCode.UInt64:
207                                 case TypeCode.Int64:
208                                         switch (tot) {
209                                         case TypeCode.Single:
210                                         case TypeCode.Double:
211                                                 return true;
212                                         }
213                                         return to == typeof (object) || (from.IsEnum && to == typeof (Enum));
214                                 case TypeCode.Single:
215                                         return tot == TypeCode.Double || to == typeof (object);
216                                 default:
217                                         /* TODO: handle valuetype -> byref */
218                                         if (to == typeof (object) && from.IsValueType)
219                                                 return true;
220
221                                         return to.IsAssignableFrom (from);
222                                 }
223                         }
224
225                         private static bool check_arguments (Type[] types, ParameterInfo[] args) {
226                                 for (int i = 0; i < types.Length; ++i) {
227                                         if (!check_type (types [i], args [i].ParameterType))
228                                                 return false;
229                                 }
230                                 return true;
231                         }
232
233                         public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
234                         {
235                                 MethodBase m;
236                                 int i, j;
237                                 if (match == null)
238                                         throw new ArgumentNullException ("match");
239                                 /* first look for an exact match... */
240                                 for (i = 0; i < match.Length; ++i) {
241                                         m = match [i];
242                                         ParameterInfo[] args = m.GetParameters ();
243                                         if (args.Length != types.Length)
244                                                 continue;
245                                         for (j = 0; j < types.Length; ++j) {
246                                                 if (types [j] != args [j].ParameterType)
247                                                         break;
248                                         }
249                                         if (j == types.Length)
250                                                 return m;
251                                 }
252                                 for (i = 0; i < match.Length; ++i) {
253                                         m = match [i];
254                                         ParameterInfo[] args = m.GetParameters ();
255                                         if (args.Length != types.Length)
256                                                 continue;
257                                         if (!check_arguments (types, args))
258                                                 continue;
259                                         return m;
260                                 }
261                                 return null;
262                         }
263
264                         public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
265                         {
266                                 if (match == null)
267                                         throw new ArgumentNullException ("match");
268                                 foreach (PropertyInfo m in match) {
269                                         ParameterInfo[] args = m.GetIndexParameters ();
270                                         if (args.Length != indexes.Length)
271                                                 continue;
272                                         if (!check_arguments (indexes, args))
273                                                 continue;
274                                         return m;
275                                 }
276                                 return null;
277                         }
278                 }
279         }
280 }