2005-06-05 Peter Bartok <pbartok@novell.com>
[mono.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic.CompilerServices / VBBinder.cs
1 //
2 // LateBinding.cs
3 //
4 // Author:
5 //   Marco Ridoni    (marco.ridoni@virgilio.it)
6 //   Satya Sudha K   (ksathyasudha@novell.com)
7 //
8 // (C) 2003 Marco Ridoni
9 //
10
11 //
12 // Copyright (c) 2002-2003 Mainsoft Corporation.
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34 using System;
35 using System.Collections;
36 using System.Reflection;
37 using System.Globalization;
38 using Microsoft.VisualBasic;
39 using System.ComponentModel;
40
41
42 namespace Microsoft.VisualBasic.CompilerServices
43 {
44         [StandardModule, EditorBrowsableAttribute(EditorBrowsableState.Never)]
45         public class VBBinder : Binder
46         {
47                 public VBBinder() : base()
48                 {
49                 }
50
51                 public VBBinder(bool [] CopyBack) : base()
52                 {
53                         byRefFlags = CopyBack;
54                 }
55
56                 private class BinderState
57                 {
58                         public object[] originalArgs;
59                         public bool[] byRefFlags;
60                 }
61
62
63                 public enum ConversionType {
64                         Exact = 0,
65                         Widening,
66                         Narrowing,
67                         None = -1
68                 }
69
70                 public override FieldInfo BindToField(
71                         BindingFlags bindingAttr,
72                         FieldInfo[] match,
73                         object value,
74                         CultureInfo culture
75                         )
76                 {
77                         return null;
78                 }
79
80                 private bool[] byRefFlags;
81                 private Type objectType;
82                 private string bindToName;
83
84                 // This method selects a suitable method for the given arguments
85                 // Step 1 : Filter out all the methods that are not applicable
86                 // Step 2 : Out of the remaining methods, retain only the methods of the most derived types
87                 // Step 3 : Get the kind of conversions (Widening, Exact, Narrowing) to be made to the 
88                 //          arguments to make them applicable. Remember the best match found so far. 
89                 //          If two or more candidates require narrowing conversions - Report error
90                 //          If two candidates X and Y require widening conversions, then
91                 //              * select X if conversions from parameters of X to correspodning parameters
92                 //                of Y are all widening.
93                 //              * select Y if conversions from parameters of Y to correspodning parameters
94                 //                of X are all widening.
95                 //              * otherwise ambiguous
96                 // Step 4: Once a best match of found, contruct a new argument list for that method using 
97                 //         the given parameters :
98                 //              * If ParamArray parameters are present then put all the corresponding arguments
99                 //                into an Array
100                 //                For example, while invoking a method 
101                 //                      'F (a As Integer, b as Integer, ParamArray c() As Integer)'
102                 //                like
103                 //                      'F (1,2,3,4,5,6}'
104                 //                the new argument list should look like (1,2 {3,4,5,6})
105                 //              - Note : Named arguments dont come into picture here as they are not supported
106                 //                       with ParamArray parameters
107                 //              * Create an argument order;
108                 //              * If an argument is Missing or the corresponding argOrder entry is -1, 
109                 //                create an argument with the parameter's default value.
110                 //              * Perform appropriate conversions.
111                 //              * set the 'ByRefFlags array properly ('ByRefFlags' is an array to indicate,
112                 //                which arguments matched a 'ByRef' parameter)
113                 public override MethodBase BindToMethod(
114                         BindingFlags bindingAttr,
115                         MethodBase[] match,
116                         ref object[] args,
117                         ParameterModifier[] modifiers,
118                         CultureInfo culture,
119                         string[] names,
120                         out object state)
121                 {
122                         // Store the original arguments to the method in a state object.
123                         BinderState binderState = new BinderState();
124                         binderState.originalArgs = args;
125                         binderState.byRefFlags = this.byRefFlags;
126                         state = binderState;
127
128                         MethodBase mbase = null;
129
130                         if(match == null || match.Length == 0)
131                                 throw new ArgumentNullException();
132
133                         ArrayList candidates = new ArrayList ();
134                         // Get the list of all suitable methods
135                         string errMsg = "";
136                         // Step 1:
137                         for (int index = 0; index < match.Length; index ++) {
138                                 if (IsApplicable (match [index], names, args, ref errMsg))
139                                         candidates.Add (match [index]);
140                         }
141
142                         if (candidates.Count == 0) {
143                                 if (match.Length == 1 && errMsg != "")
144                                         throw new ArgumentException (errMsg);
145                                 return null;
146                         }
147
148                         // Step 2:
149                         MemberInfo[] tempMatchList = GetMostDerivedMembers (candidates);
150                         MethodBase[] filteredMatchList = new MethodBase [tempMatchList.Length];
151                         for (int index = 0; index < tempMatchList.Length; index ++)
152                                 filteredMatchList [index] = (MethodBase) tempMatchList [index];
153
154                         ConversionType bestMatch = ConversionType.None;
155                         int numWideningConversions = 0, numNarrowingConversions = 0;
156                         ArrayList narrowingConv = new ArrayList ();
157                         ArrayList wideningConv = new ArrayList ();
158                         // Step 3:
159                         for(int x = 0; x < filteredMatchList.Length; x++)
160                         {
161                                 ParameterInfo[] parameters = filteredMatchList [x].GetParameters();
162                                 ConversionType ctype = GetConversionType (parameters, args, names);
163                                 if (ctype == ConversionType.None)
164                                         continue;
165                                 if (ctype == ConversionType.Widening)
166                                         wideningConv.Add (filteredMatchList[x]);
167                                 if (ctype == ConversionType.Narrowing)
168                                         narrowingConv.Add (filteredMatchList[x]);
169                                 if (bestMatch == ConversionType.None || ctype < bestMatch) {
170                                         bestMatch = ctype;
171                                         if (ctype == ConversionType.Narrowing)
172                                                 numNarrowingConversions ++;
173                                         if (ctype == ConversionType.Widening)
174                                                 numWideningConversions ++;
175                                         mbase = filteredMatchList [x];
176                                 } else if (bestMatch == ctype) {
177                                         if (bestMatch == ConversionType.Widening || bestMatch == ConversionType.Exact) {
178                                                 // Got a widening conversion before also.
179                                                 // Find the best among the two
180                                                 int closestMatch = GetClosestMatch (mbase, filteredMatchList [x], args.Length);
181                                                 if (closestMatch == -1) { // Ambiguous
182                                                         numWideningConversions ++;
183                                                 }
184                                                 else 
185                                                         numWideningConversions = 0;
186                                                 if (closestMatch == 1)
187                                                         mbase = filteredMatchList [x];
188                                         } else {
189                                                 numNarrowingConversions ++;
190                                         }
191                                 }
192                         }
193
194                         if (bestMatch == ConversionType.Narrowing && numNarrowingConversions > 1) {
195                                 //TODO : print the methods too
196                                 throw new AmbiguousMatchException ("No overloaded '" + this.objectType + "." + this.bindToName + "' can be called without a narrowing conversion");
197                         }
198
199                         if ((bestMatch == ConversionType.Widening || bestMatch == ConversionType.Exact) && numWideningConversions > 1) {
200                                 //TODO : print the methods too
201                                 throw new AmbiguousMatchException ("No overloaded '" + this.objectType + "." + this.bindToName + "' can be called without a widening conversion");
202                         }
203
204                         if (mbase == null)
205                                 return null;
206
207                         ParameterInfo[] pars = mbase.GetParameters ();
208                         if (pars.Length == 0)
209                                 return mbase;
210
211                         int [] argOrder = null;
212                         if (!CreateArgOrder (pars, names, args.Length, out argOrder))
213                                 return null; 
214
215                         // Step 4:
216                         if (UsesParamArray (pars)) {
217                                 int index = 0;
218                                 int paramArrayIndex = pars.GetUpperBound (0);
219                                 Type paramArrayType = pars [paramArrayIndex].ParameterType;
220                                 Array paramArgs = Array.CreateInstance (paramArrayType.GetElementType (), args.Length - paramArrayIndex);
221                                 bool isArgArray = false;
222                                 if (pars.GetUpperBound (0) + 1 == args.Length) {
223                                         if (args [pars.GetUpperBound (0)].GetType().IsArray)
224                                                 isArgArray = true;
225                                 }
226
227                                 if (!isArgArray) {
228                                         for (int y = paramArrayIndex; y < args.Length; y ++) {
229                                                 Type dest_type = paramArrayType;
230                                                 if (!args [y].GetType ().IsArray) {
231                                                         dest_type = paramArrayType.GetElementType ();
232                                                 }
233                                                 if((args [y] = ObjectType.CTypeHelper (args[y], dest_type)) != null) {
234                                                         paramArgs.SetValue (args [y], index);
235                                                 } else
236                                                         return null;
237                                                 index ++;
238                                         }
239
240                                         object[] newArgs = new object [pars.Length];
241                                         Array.Copy (args, newArgs, paramArrayIndex);
242                                         newArgs [newArgs.GetUpperBound (0)] = paramArgs;
243                                         args = newArgs;
244                                 }
245                         }
246
247                         object[] newArguments = new object [pars.Length];
248                         args.CopyTo (newArguments, 0);
249                         if (!CreateArgOrder (pars, names, args.Length, out argOrder))
250                                 return null;
251                         int numExpectedArgs = pars.Length;
252                         if (UsesParamArray (pars))
253                                 numExpectedArgs --;
254
255                         int argIndex = 0;
256                         
257                         for(int y = 0; y < numExpectedArgs; y++)
258                         {
259                                 argIndex = y;
260                                 if (argIndex < argOrder.Length)
261                                         argIndex = argOrder [y];
262                                 if (argIndex == -1 || argIndex >= args.Length) // Missing arguments (trailing)
263                                         newArguments [y] = pars [y].DefaultValue;
264                                 else if (argIndex < args.Length) {
265                                         if (args [argIndex] is Missing)
266                                                 newArguments [y] = pars [y].DefaultValue;
267                                         else 
268                                                 newArguments [y] = args [argIndex];
269                                 }
270                         }
271
272                         for(int y = 0; y < numExpectedArgs; y++) {
273                                 if (newArguments [y] == null)
274                                         continue;
275
276                                 if((newArguments [y] = ObjectType.CTypeHelper (newArguments[y], pars[y].ParameterType)) == null)
277                                         return null;
278                         }
279
280                         args = newArguments;
281                         return mbase;
282                 }
283
284                 private int GetClosestMatch (MethodBase bestMatch, MethodBase candidate, int argCount) {
285                         // flag to indicate which one has been better so far
286                         // -1 : none is better than other
287                         // 0 : bestMatch has been better so far
288                         // 1 : candidate is better than bestMatch
289                         int isBetter = -2;
290                         ParameterInfo[] bestMatchParams = bestMatch.GetParameters ();
291                         ParameterInfo[] candidateParams = candidate.GetParameters ();
292                         int paramArrayIndex1 = -1, paramArrayIndex2 = -1;
293                         if (UsesParamArray (bestMatchParams)) {
294                                 paramArrayIndex1 = (bestMatchParams.Length > 0) ? (bestMatchParams.Length - 1) : -1;
295                         }
296
297                         if (UsesParamArray (candidateParams)) {
298                                 paramArrayIndex2 = (candidateParams.Length > 0) ? (candidateParams.Length - 1) : -1;
299                         }
300
301                         for (int i = 0; i < argCount; i ++) {
302                                 int index1 = i, index2 = i;
303                                 Type bestMatchParamsType = null;
304                                 Type candParamType = null;
305                                 if (i >= paramArrayIndex1 && paramArrayIndex1 != -1) {
306                                         index1 = paramArrayIndex1;
307                                         bestMatchParamsType = bestMatchParams [index1].ParameterType.GetElementType ();
308                                 } else 
309                                         bestMatchParamsType = bestMatchParams [index1].ParameterType;
310                                 if (i >= paramArrayIndex2 && paramArrayIndex2 != -1) {
311                                         index2 = paramArrayIndex2;
312                                         candParamType = candidateParams [index2].ParameterType.GetElementType ();
313                                 } else
314                                         candParamType = candidateParams [index2].ParameterType;
315
316
317                                 if (bestMatchParamsType == candParamType)
318                                         continue;
319
320                                 if (ObjectType.IsWideningConversion (bestMatchParamsType, candParamType)) {
321                                         // ith param of candidate is wider than that of bestMatch
322                                         if (isBetter == -2) {
323                                                 isBetter = 0;
324                                                 continue;
325                                         } else if (isBetter != 0) {
326                                                 isBetter = -1;
327                                                 continue;
328                                         }
329                                         isBetter = 0;
330                                         
331                                 } else if (ObjectType.IsWideningConversion (candParamType, bestMatchParamsType)) {
332                                         // ith param of bestMatch is wider than that of candidate
333                                         if (isBetter == -2) {
334                                                 isBetter = 1;
335                                                 continue;
336                                         } else if (isBetter != 1) {
337                                                 isBetter = -1;
338                                                 continue;
339                                         }
340                                         isBetter = 1;
341                                 }
342                         }
343
344                         if (isBetter == -2) {
345                                 // corresponding parameters of both methods have same types
346                                 // the method having max no of fixed parameters is better
347                                 if (paramArrayIndex1 == -1 && paramArrayIndex2 != -1)
348                                                 return 0;
349                                 if (paramArrayIndex1 != -1 && paramArrayIndex2 == -1)
350                                                 return 1;
351                                 return ((paramArrayIndex1 < paramArrayIndex2) ? 1 : 0);
352                         }
353
354                         return isBetter;
355                 }
356
357                 // Determines is there is any 'ParamArray' parameter in the given set of param
358                 internal static bool UsesParamArray (ParameterInfo [] pars) {
359                         if (pars == null || pars.Length == 0)
360                                 return false;
361                         ParameterInfo lastParam = pars [pars.GetUpperBound (0)];
362                         object[] attrs = lastParam.GetCustomAttributes (typeof (System.ParamArrayAttribute), false);
363                         if (attrs == null || attrs.Length == 0)
364                                 return false;
365                         return true;
366                 }
367
368                 // Gets the number of parameters that are neither optional not ParamArray
369                 internal static int CountStandardParams (ParameterInfo [] pars) {
370                         if (pars.Length == 0)
371                                 return 0;
372                         int count = pars.Length;
373                         for (int index = 0; index < pars.Length; index ++) {
374                                 ParameterInfo param = pars [index];
375                                 if (param.IsOptional)
376                                         return index;
377                                 if (index + 1 == pars.Length) {
378                                         object[] attrs = param.GetCustomAttributes (typeof (System.ParamArrayAttribute), false);
379                                         if (attrs != null && attrs.Length > 0)
380                                                 return index;
381                                 }
382                         }
383                         return count;
384                 }
385
386                 // Determines the kind of conversions from argument types to parameter types
387                 private ConversionType GetConversionType (ParameterInfo[] parameters, object[] args, string[] names) {
388                         int numParams = parameters.Length;
389                         int numArgs = args.Length;
390                         int numFixedParams = CountStandardParams (parameters);
391
392                         if (numParams == 0) {
393                                 if (numArgs == 0)
394                                         return ConversionType.Exact;
395                                 else
396                                         return ConversionType.None;
397                         }
398
399                         bool usesParamArray = UsesParamArray (parameters);
400                         if (numFixedParams == 0 && numArgs == 0)
401                                 return ConversionType.Exact;
402
403                         if (numArgs < numFixedParams)
404                                 return ConversionType.None;
405
406                         ConversionType ctype = ConversionType.None;
407                         bool isLastParam = false;
408                         int paramIndex = 0, argIndex = 0;
409                         int [] argOrder = null;
410                         if (!CreateArgOrder (parameters, names, numArgs, out argOrder))
411                                 return ConversionType.None;
412
413                         for (int index = 0; index < numArgs; index ++) {
414                                 argIndex = argOrder [index];
415                                 paramIndex = index;
416                                 if (paramIndex >= numFixedParams)
417                                          if (usesParamArray) {
418                                                 paramIndex = parameters.GetUpperBound (0);
419                                                 isLastParam = true;
420                                         }
421
422                                 ConversionType currentCType = ConversionType.None;
423                                 Type type1 = null;
424                                 if (argIndex == -1) {
425                                         currentCType = ConversionType.Exact;
426                                         if (ctype < currentCType)
427                                                 ctype = currentCType;
428                                         continue;
429                                 }
430                                 if (args [argIndex] != null)
431                                         type1 = args [argIndex].GetType ();
432                                 Type type2 = parameters [paramIndex].ParameterType;
433                                 if (type2.IsByRef)
434                                         type2 = type2.GetElementType ();
435                                 if (usesParamArray && isLastParam) {
436                                         if (type1.IsArray) {
437                                                 if (type1.GetElementType () == type2.GetElementType ())
438                                                         currentCType = ConversionType.Exact;
439                                                 else if (ObjectType.IsWideningConversion (type1, type2))
440                                                         currentCType = ConversionType.Widening;
441                                                 else 
442                                                         currentCType = ConversionType.Narrowing;
443                                         } else {
444                                                 Type elementType = type2.GetElementType ();
445                                                 if (type1 == elementType)
446                                                         currentCType = ConversionType.Exact;
447                                                 else if (ObjectType.IsWideningConversion (type1, elementType))
448                                                         currentCType = ConversionType.Widening;
449                                                 else 
450                                                         currentCType = ConversionType.Narrowing;
451                                         }
452                                         if (currentCType == ConversionType.Narrowing || ctype < currentCType)
453                                                 ctype = currentCType;
454
455                                 } else {
456                                         if (type1 == type2) {
457                                                 currentCType = ConversionType.Exact;
458                                                 if (ctype < currentCType) {
459                                                         ctype = ConversionType.Exact;
460                                                 }
461                                         } else if (ObjectType.IsWideningConversion (type1, type2)) {
462                                                 currentCType = ConversionType.Widening;
463                                                 if (ctype < currentCType)
464                                                         ctype = ConversionType.Widening;
465                                         } else 
466                                                 ctype = ConversionType.Narrowing;
467                                 }
468                         }
469
470                         return ctype;
471                 }
472
473                 public override object ChangeType(
474                         object value,
475                         Type myChangeType,
476                         CultureInfo culture
477                         )
478                 {               
479                         TypeCode src_type = Type.GetTypeCode (value.GetType());                 
480                         TypeCode dest_type = Type.GetTypeCode (myChangeType);
481                         
482                         switch (dest_type) {
483                                 case TypeCode.String:
484                                         switch (src_type) {
485                                                 case TypeCode.SByte:                                            
486                                                 case TypeCode.Byte:
487                                                         return (StringType.FromByte ((byte)value));
488                                                 case TypeCode.UInt16:
489                                                 case TypeCode.Int16:
490                                                         return (StringType.FromShort ((short)value));   
491                                                 case TypeCode.UInt32:                                   
492                                                 case TypeCode.Int32:
493                                                         return (StringType.FromInteger ((int)value));                                           
494                                                 case TypeCode.UInt64:   
495                                                 case TypeCode.Int64:
496                                                         return (StringType.FromLong ((long)value));                                             
497                                                 case TypeCode.Char:
498                                                         return (StringType.FromChar ((char)value));                                                     
499                                                 case TypeCode.Single:
500                                                         return (StringType.FromSingle ((float)value));  
501                                                 case TypeCode.Double:
502                                                         return (StringType.FromDouble ((double)value));                                                                                                                                         
503                                                 case TypeCode.Boolean:
504                                                         return (StringType.FromBoolean ((bool)value));  
505                                                 case TypeCode.Object:
506                                                         return (StringType.FromObject (value));                                                                                                                                                                                                                         
507                                         }
508                                         break;
509                                         
510                                 case TypeCode.Int32:
511                                 case TypeCode.UInt32:   
512                                         switch (src_type) {                                             
513                                                 case TypeCode.String:                           
514                                                         return (IntegerType.FromString ((string)value));        
515                                                 case TypeCode.Object:                           
516                                                         return (IntegerType.FromObject (value));                                                                                
517                                         }
518                                         break;  
519
520                                 case TypeCode.Int16:
521                                 case TypeCode.UInt16:   
522                                         switch (src_type) {                                             
523                                                 case TypeCode.String:                           
524                                                         return (ShortType.FromString ((string)value));          
525                                                 case TypeCode.Object:                           
526                                                         return (ShortType.FromObject (value));                                                                          
527                                         }
528                                         break;  
529                                 case TypeCode.Object:
530                                         return ((Object) value);                                                                                                
531                         }
532                         return null;
533                 }
534
535                 public override void ReorderArgumentArray(
536                         ref object[] args,
537                         object state
538                         )
539                 {
540
541                 }
542
543                 public override MethodBase SelectMethod(
544                         BindingFlags bindingAttr,
545                         MethodBase[] match,
546                         Type[] types,
547                         ParameterModifier[] modifiers
548                         )
549                 {
550                         return null;
551                 }
552
553                 public override PropertyInfo SelectProperty(
554                         BindingFlags bindingAttr,
555                         PropertyInfo[] match,
556                         Type returnType,
557                         Type[] indexes,
558                         ParameterModifier[] modifiers
559                         )               
560                 {
561                         return null;
562                 }
563                 
564                 public Object InvokeMember (string name, 
565                                             BindingFlags flags,
566                                             Type objType,
567                                             IReflect objReflect,
568                                             object target,
569                                             object[] args,
570                                             ParameterModifier[] modifiers,
571                                             CultureInfo culture,
572                                             string[] paramNames) {
573
574                         this.objectType = objType;
575                         this.bindToName = name;
576                         if (name == null || name.Equals ("")) {
577                                 // Must be a default property
578                                 Type t = objType;
579                                 while (t != null) {
580                                         object[] attrArray = t.GetCustomAttributes (typeof (DefaultMemberAttribute), false);
581                                         if (attrArray != null && attrArray.Length != 0) {
582                                                 name = ((DefaultMemberAttribute) attrArray[0]).MemberName;
583                                                 break;
584                                         }
585                                         // not found, search in the base type
586                                         t = t.BaseType;
587                                 }
588                         }
589
590                         if (name == null || name.Equals ("")) 
591                                 throw new MissingMemberException ("No default members defined for type '" + objType + "'");
592
593                         MemberInfo[] memberinfo = GetMembers (objReflect, objType, name, flags);
594
595                         if (memberinfo == null || memberinfo.Length == 0) {
596                                 throw new MissingMemberException ("No member '" + name + "' defined for type '" + objType + "'");
597                         }
598                         
599                         object objState = null;
600                         object retVal = null;
601                         if (memberinfo [0] is MethodBase) {
602                                 MethodBase[] methodbase = new MethodBase [memberinfo.Length];
603                                 for (int index = 0; index < memberinfo.Length; index ++)
604                                         methodbase [index] = (MethodBase) memberinfo [index];
605
606                                 MethodBase mbase = BindToMethod (flags,
607                                                                  methodbase,
608                                                                  ref args, modifiers,
609                                                                  culture,
610                                                                  paramNames,
611                                                                  out objState);
612                                 if (mbase == null)
613                                         throw new MissingMemberException ("No member '" + name +
614                                                  "' defined for type '" + objType + "' which takes the given set of arguments");
615
616                                 MethodInfo mi = (MethodInfo) mbase;
617                                 retVal =  mi.Invoke (target, args);
618                                 // Modify the byRefFlags approproately
619                                 // Also copy the modified arguments back
620                                 if (objState != null && byRefFlags != null) {
621                                         BinderState state = (BinderState) objState;
622                                         object [] originalArgs = state.originalArgs;
623                                         int[] paramOrder = null;
624                                         ParameterInfo [] pars = mi.GetParameters ();
625                                         if (!CreateParamOrder (pars, paramNames, args.Length, out paramOrder))
626                                                 return null;    // Should never happen
627                                         int paramIndex = 0;
628                                         for (int index = 0; index < originalArgs.Length; index++) {
629                                                 paramIndex = index;
630                                                 if (paramIndex < paramOrder.Length)
631                                                         paramIndex = paramOrder [index];
632                                                 if (paramIndex == -1)
633                                                         continue;       // Should not happen
634                                                 if (paramIndex >= pars.Length)
635                                                         paramIndex = pars.GetUpperBound (0);
636                                                 ParameterInfo p = pars [paramIndex];
637                                                 if (p.ParameterType.IsByRef) {
638                                                         if (byRefFlags [index] != false)
639                                                                 byRefFlags [index] = true;
640                                                         originalArgs [index] = args [paramIndex];
641                                                 } else
642                                                         byRefFlags [index] = false;
643                                         }
644                                 }
645                         }
646
647                         return retVal;
648                 }
649
650                 // Determines whether a given method can be invoked with a given set of arguments
651                 private bool IsApplicable (MethodBase mb, string [] names, object [] args, ref string errorMsg) {
652                         ParameterInfo [] parameters = mb.GetParameters ();
653                         int numFixedParams = CountStandardParams (parameters);
654                         int numParams = parameters.Length;
655                         int argCount = 0;
656                         if (args != null)
657                                 argCount = args.Length;
658
659                         if (numParams == numFixedParams)        // No ParamArray or Optional params
660                                 if (argCount != numParams)
661                                         return false;
662                         
663                         if (argCount < numFixedParams)
664                                 return false;
665
666                         bool usesParamArray = UsesParamArray (parameters);
667                         if (!usesParamArray && (argCount > numParams))
668                                 return false;
669
670                         if (usesParamArray && (names != null && names.Length > 0)) {
671                                 errorMsg += "\n\tNamed argument cannot match ParamArray parameters";
672                                 return false;
673                         }
674
675                         int paramIndex = 0, argIndex = 0;
676                         bool isLastParam = false;
677                         int [] argOrder = null;
678                         if (!CreateArgOrder (parameters, names, argCount, out argOrder))
679                                 return false;
680
681                         // We know that we have arguments for all fixed parameters atleast
682                         for (int index = 0; index < argCount; index ++) {
683                                 Type argType = null;
684                                 Type paramType = null;
685                                 isLastParam = false;
686                                 paramIndex = index;
687                                 argIndex = argOrder [index];
688                                 if (argIndex == -1) // Missing argument, we will use the default value.
689                                         continue;
690                                 if (index >= numFixedParams)
691                                         if (usesParamArray) {
692                                                 paramIndex = numParams - 1;
693                                                 isLastParam = true;
694                                         }
695
696                                 paramType = parameters [paramIndex].ParameterType;
697                                 if (args [argIndex] != null) {
698                                         argType = args [argIndex].GetType ();
699                                         if (usesParamArray && isLastParam) {
700                                                 // ParamArray parameter of type 'T'. We can either have an 
701                                                 // argument which is an array of type T, or 'n' number of 
702                                                 // arguments that are of/convertible to type 'T'
703                                                 if (!argType.IsArray) {
704                                                         Type elementType = paramType.GetElementType ();
705                                                         if (!ObjectType.ImplicitConversionExists (argType, elementType))
706                                                                 return false;
707                                                 } else {
708                                                         Type elementType = paramType.GetElementType ();
709                                                         argType = argType.GetElementType ();
710                                                         if (!elementType.IsAssignableFrom (argType))
711                                                                 return false;
712                                                 }
713                                         } else {
714                                                 if (paramType.IsByRef)
715                                                         paramType = paramType.GetElementType ();
716                                                 if (!ObjectType.ImplicitConversionExists (argType, paramType))
717                                                         return false;
718                                         }
719         
720                                 }
721                         }
722                         return true;
723                 }
724
725                 
726                 // Creates argument order
727                 // If argument names are present, then argument order is created according to paramters
728                 // For missing arguments, the corresponding entry wil be -1
729                 //    For example, if a method 'F (a As Integer,b As Integer,c As Integer,d As Integer)' 
730                 //    is invoked like 'F (c := 1, a := 2, d :=3), then the argument order will be 
731                 //    {1, -1, 0, 2}
732                 // This method also checks for duplicate argument names, missing parameters, etc.
733                 //
734                 // If no argument names are present, the order of arguments is expected to match that 
735                 // of the parameters. So, in this case, the order will be {0, 1, 2, 3...., numArgs - 1}
736                 private bool CreateArgOrder (ParameterInfo [] pars, string [] names, int numArgs, out int [] argOrder) 
737                 {
738                         argOrder = null;
739                         if (names == null || names.Length == 0) {
740                                 argOrder = new int [numArgs];
741                                 for (int index = 0; index < numArgs; index ++)
742                                         argOrder [index] = index;
743                         } else {
744
745                                 int numParamsMatched = 0;
746                                 argOrder = new int [pars.Length];
747                                 for (int index = 0; index < argOrder.Length; index ++) 
748                                         argOrder [index] = -1;
749                                 for (int paramIndex = 0; paramIndex < pars.Length; paramIndex ++) {
750                                         string paramName = pars [paramIndex].Name.ToLower ();
751                                         bool foundArgForParam = false;
752                                         for (int argindex = 0; argindex < names.Length; argindex ++) {
753                                                 string argName = names [argindex].ToLower ();
754                                                 if (paramName.Equals (argName)) {
755                                                         foundArgForParam = true;
756                                                         if (argOrder [paramIndex] != -1)
757                                                                 throw new ArgumentException ("Argument '" + 
758                                                                         argName + "' specified multiple times");
759                                                         argOrder [paramIndex] = argindex;
760                                                         numParamsMatched ++;
761                                                 }
762                                         }
763
764                                         if (!foundArgForParam && !pars [paramIndex].IsOptional)
765                                                 return false;
766                                 } 
767
768                                 if (numParamsMatched != numArgs) 
769                                         return false;   // We have some invalid paramnames
770                         }
771                         return true;
772                 }
773
774                 // Creates parameter order
775                 // Similar to CreateArgOrder method, but here order is created according to names/arguments
776                 private bool CreateParamOrder (ParameterInfo [] pars, string [] names, int numArgs, out int [] paramOrder) 
777                 {
778                         paramOrder = null;
779                         if (names == null || names.Length == 0) {
780                                 paramOrder = new int [numArgs];
781                                 for (int index = 0; index < numArgs; index ++)
782                                         paramOrder [index] = index;
783                         } else {
784
785                                 paramOrder = new int [names.Length];
786                                 for (int index = 0; index < paramOrder.Length; index ++) 
787                                         paramOrder [index] = -1;
788                                 for (int argindex = 0; argindex < names.Length; argindex ++) {
789                                         string argName = names [argindex].ToLower ();
790                                         bool foundParamForArg = false;
791                                         for (int paramIndex = 0; paramIndex < pars.Length; paramIndex ++) {
792                                                 string paramName = pars [paramIndex].Name.ToLower ();
793                                                 if (paramName.Equals (argName)) {
794                                                         paramOrder [argindex] = paramIndex;
795                                                         foundParamForArg = true;
796                                                 }
797                                                 if (! foundParamForArg)
798                                                         return false;
799                                         }
800                                 }
801                         }
802                         return true;
803                 }
804
805                 private static MemberInfo [] GetMostDerivedMembers (ArrayList memberinfo) {
806                         int i = 0;
807                         int numElementsEliminated = 0;
808                         for (i = 0; i < memberinfo.Count; i++) {
809                                 MemberInfo mi = (MemberInfo) memberinfo [i];
810                                 for (int j = i + 1; j < memberinfo.Count; j++) {
811                                         bool eliminateBaseMembers = false;
812                                         MemberInfo thisMember = (MemberInfo) memberinfo [j];
813                                         Type t1 = mi.DeclaringType;
814                                         Type t2 = thisMember.DeclaringType;
815                                         if (mi.MemberType == MemberTypes.Field)
816                                                 eliminateBaseMembers = true;
817                                         if (mi.MemberType == MemberTypes.Method) {
818                                                 MethodInfo methodinfo = (MethodInfo) mi;
819                                                 if (methodinfo.IsVirtual)
820                                                         eliminateBaseMembers = true;
821                                         }
822                                         if (mi.MemberType == MemberTypes.Property) {
823                                                 PropertyInfo propertyinfo = (PropertyInfo) mi;
824                                                 MethodInfo method = propertyinfo.GetGetMethod ();
825                                                 if (method.IsVirtual)
826                                                         eliminateBaseMembers = true;
827                                         }
828                                         if (eliminateBaseMembers) {
829                                                 if (t1.IsSubclassOf (t2)) {
830                                                         memberinfo [j] = null;
831                                                         numElementsEliminated ++;
832                                                 } else if (t2.IsSubclassOf (t1)) {
833                                                         memberinfo [i] = null;
834                                                         numElementsEliminated ++;
835                                                 }
836                                         }
837                                 }
838                         }
839
840                         MemberInfo [] newMemberList = new MemberInfo [memberinfo.Count - numElementsEliminated];
841                         int newIndex = 0;
842                         for (int index = 0; index < memberinfo.Count; index ++) {
843                                 if (memberinfo [index] != null) {
844                                         newMemberList [newIndex ++] = (MemberInfo) memberinfo [index];
845                                 }
846                         }
847                         return newMemberList;
848                 }
849
850                 internal MemberInfo [] GetMembers (IReflect objReflect, Type objType, string name, BindingFlags invokeFlags) 
851                 {
852                         MemberInfo [] mi = objReflect.GetMember (name, invokeFlags);
853                         if (mi == null || mi.Length == 0)
854                                 return null;
855
856                         for (int index = 0; index < mi.Length; index ++)
857                         {
858                                 if (mi [index].MemberType == MemberTypes.Property) {
859                                         PropertyInfo propinfo = (PropertyInfo) mi [index];
860                                         if ((invokeFlags & BindingFlags.GetProperty) == BindingFlags.GetProperty) 
861                                                 mi [index] = propinfo.GetGetMethod ();
862                                         else if ((invokeFlags & BindingFlags.SetProperty) == BindingFlags.SetProperty)
863                                                 mi [index] = propinfo.GetSetMethod ();
864                                 }
865                         }
866                         return mi;
867                 }
868         }
869 }