2005-05-13 Atsushi Enomoto <atsushi@ximian.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[] args;
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                 public override MethodBase BindToMethod(
85                         BindingFlags bindingAttr,
86                         MethodBase[] match,
87                         ref object[] args,
88                         ParameterModifier[] modifiers,
89                         CultureInfo culture,
90                         string[] names,
91                         out object state
92                         )
93                 {
94                         // Store the arguments to the method in a state object.
95                         BinderState binderState = new BinderState();
96                         object[] arguments = new Object[args.Length];
97                         args.CopyTo(arguments, 0);
98                         binderState.args = arguments;
99                         state = binderState;
100
101                         MethodBase mbase = null;
102                         Type applicable_type = null;
103
104                         if(match == null || match.Length == 0)
105                                 throw new ArgumentNullException();
106
107                         /*
108                                 // Handle delegates
109                                 if (match [0].Name == "Invoke") {
110                                         // TODO
111                                 }
112                         */
113
114                         ArrayList candidates = new ArrayList ();
115                         // Get the list of all suitable methods
116                         for (int index = 0; index < match.Length; index ++) {
117                                 if (IsApplicable (match [index], args))
118                                         candidates.Add (match [index]);
119                         }
120
121                         MemberInfo[] tempMatchList = GetMostDerivedMembers (candidates);
122                         MethodBase[] filteredMatchList = new MethodBase [tempMatchList.Length];
123                         for (int index = 0; index < tempMatchList.Length; index ++)
124                                 filteredMatchList [index] = (MethodBase) tempMatchList [index];
125
126                         ConversionType bestMatch = ConversionType.None;
127                         int numWideningConversions = 0, numNarrowingConversions = 0;
128                         ArrayList narrowingConv = new ArrayList ();
129                         ArrayList wideningConv = new ArrayList ();
130                         for(int x = 0; x < filteredMatchList.Length; x++)
131                         {
132                                 ParameterInfo[] parameters = filteredMatchList [x].GetParameters();
133                                 ConversionType ctype = GetConversionType (parameters, args);
134                                 if (ctype == ConversionType.None)
135                                         continue;
136                                 if (ctype == ConversionType.Widening)
137                                         wideningConv.Add (filteredMatchList[x]);
138                                 if (ctype == ConversionType.Narrowing)
139                                         narrowingConv.Add (filteredMatchList[x]);
140                                 if (bestMatch == ConversionType.None || ctype < bestMatch) {
141                                         bestMatch = ctype;
142                                         if (ctype == ConversionType.Narrowing)
143                                                 numNarrowingConversions ++;
144                                         if (ctype == ConversionType.Widening)
145                                                 numWideningConversions ++;
146                                         mbase = filteredMatchList [x];
147                                 } else if (bestMatch == ctype) {
148                                         if (bestMatch == ConversionType.Widening || bestMatch == ConversionType.Exact) {
149                                                 // Got a widening conversion before also.
150                                                 // Find the best among the two
151                                                 int closestMatch = GetClosestMatch (mbase, filteredMatchList [x], args.Length);
152                                                 if (closestMatch == -1) {
153                                                         numWideningConversions ++;
154                                                 }
155                                                 else if (closestMatch == 1)
156                                                         mbase = filteredMatchList [x];
157                                         } else {
158                                                 numNarrowingConversions ++;
159                                         }
160                                 }
161                         }
162
163                         if (bestMatch == ConversionType.Narrowing && numNarrowingConversions > 1) {
164                                 //TODO : print the methods too
165                                 throw new AmbiguousMatchException ("No overloaded '" + this.objectType + "." + this.bindToName + "' can be called without a narrowing conversion");
166                         }
167                         if ((bestMatch == ConversionType.Widening || bestMatch == ConversionType.Exact) && numWideningConversions > 1) {
168                                 //TODO : print the methods too
169                                 throw new AmbiguousMatchException ("No overloaded '" + this.objectType + "." + this.bindToName + "' can be called without a widening conversion");
170                         }
171
172                         if (mbase == null)
173                                 return null;
174
175                         int count = 0;
176                         ParameterInfo[] pars = mbase.GetParameters ();
177                         if (pars.Length == 0)
178                                 return mbase;
179                         int numFixedParams = CountStandardParams (pars);
180
181                         if (UsesParamArray (pars)) {
182                                 int index = 0;
183                                 int paramArrayIndex = pars.GetUpperBound (0);
184                                 Type paramArrayType = pars [paramArrayIndex].ParameterType;
185                                 Array paramArgs = Array.CreateInstance (paramArrayType.GetElementType (), args.Length - paramArrayIndex);
186                                 bool isArgArray = false;
187                                 if (pars.GetUpperBound (0) + 1 == args.Length) {
188                                         if (args [pars.GetUpperBound (0)].GetType().IsArray) {
189                                                 isArgArray = true;
190                                                 count ++;
191                                         }
192                                 }
193
194                                 if (!isArgArray) {
195                                         for (int y = paramArrayIndex; y < args.Length; y ++) {
196                                                 Type dest_type = paramArrayType;
197                                                 if (!args [y].GetType ().IsArray) {
198                                                         dest_type = paramArrayType.GetElementType ();
199                                                 }
200                                                 if((args [y] = ObjectType.CTypeHelper (args[y], dest_type)) != null) {
201                                                         paramArgs.SetValue (args [y], index);
202                                                 } else
203                                                         return null;
204                                                 index ++;
205                                         }
206
207                                         object[] newArgs = new object [pars.Length];
208                                         Array.Copy (args, newArgs, paramArrayIndex);
209                                         newArgs [newArgs.GetUpperBound (0)] = paramArgs;
210                                         args = newArgs;
211                                 }
212                         }
213
214                         object[] newArguments = new object [pars.Length];
215                         args.CopyTo (newArguments, 0);
216                         int numExpectedArgs = pars.Length;
217                         if (UsesParamArray (pars))
218                                 numExpectedArgs --;
219                         for(int y = 0; y < numExpectedArgs; y++)
220                         {
221                                 if (y < args.Length && (args [y] is Missing || args[y] == null))
222                                         newArguments [y] = pars [y].DefaultValue;
223                                 else if (y >= args.Length)
224                                         newArguments [y] = pars [y].DefaultValue;
225                                 else 
226                                         newArguments [y] = args [y];
227                         }
228
229                         for(int y = 0; y < numExpectedArgs; y++) {
230                                 if (newArguments [y] == null)
231                                         return null;
232
233                                 if((newArguments [y] = ObjectType.CTypeHelper (newArguments[y], pars[y].ParameterType)) == null)
234                                         return null;
235                         }
236
237                         ((BinderState) state).args = newArguments;
238
239                         if (byRefFlags == null || pars.Length == 0) {
240                                 return mbase;
241                         }
242
243                         int paramIndex = 0;
244                         for (int index = 0; index < byRefFlags.Length; index ++) {
245                                 paramIndex = index;
246                                 if (index >= pars.Length)
247                                         paramIndex = pars.GetUpperBound (0);
248                                 ParameterInfo p = pars [paramIndex];
249                                 if (p.ParameterType.IsByRef) {
250                                         if (byRefFlags [index] != false)
251                                                 byRefFlags [index] = true;
252                                 } else
253                                         byRefFlags [index] = false;
254                         }
255
256                         return mbase;
257                 }
258
259                 private int GetClosestMatch (MethodBase bestMatch, MethodBase candidate, int argCount) {
260                         // flag to indicate which one has been better so far
261                         // -1 : none is better than other
262                         // 0 : bestMatch has been better so far
263                         // 1 : candidate is better than bestMatch
264                         int isBetter = -2;
265                         ParameterInfo[] bestMatchParams = bestMatch.GetParameters ();
266                         ParameterInfo[] candidateParams = candidate.GetParameters ();
267                         int numParams = Math.Min (bestMatchParams.Length, candidateParams.Length);
268                         int paramArrayIndex1 = -1, paramArrayIndex2 = -1;
269                         if (UsesParamArray (bestMatchParams)) {
270                                 paramArrayIndex1 = (bestMatchParams.Length > 0) ? (bestMatchParams.Length - 1) : -1;
271                         }
272
273                         if (UsesParamArray (candidateParams)) {
274                                 paramArrayIndex2 = (candidateParams.Length > 0) ? (candidateParams.Length - 1) : -1;
275                         }
276
277                         for (int i = 0; i < argCount; i ++) {
278                                 int index1 = i, index2 = i;
279                                 Type bestMatchParamsType = null;
280                                 Type candParamType = null;
281                                 if (i >= paramArrayIndex1 && paramArrayIndex1 != -1) {
282                                         index1 = paramArrayIndex1;
283                                         bestMatchParamsType = bestMatchParams [index1].ParameterType.GetElementType ();
284                                 } else 
285                                         bestMatchParamsType = bestMatchParams [index1].ParameterType;
286                                 if (i >= paramArrayIndex2 && paramArrayIndex2 != -1) {
287                                         index2 = paramArrayIndex2;
288                                         candParamType = candidateParams [index2].ParameterType.GetElementType ();
289                                 } else
290                                         candParamType = candidateParams [index2].ParameterType;
291
292
293                                 if (bestMatchParamsType == candParamType)
294                                         continue;
295
296                                 if (ObjectType.IsWideningConversion (bestMatchParamsType, candParamType)) {
297                                         // ith param of candidate is wider than that of bestMatch
298                                         if (isBetter == -2) {
299                                                 isBetter = 0;
300                                                 continue;
301                                         } else if (isBetter != 0) {
302                                                 isBetter = -1;
303                                                 continue;
304                                         }
305                                         isBetter = 0;
306                                         
307                                 } else if (ObjectType.IsWideningConversion (candParamType, bestMatchParamsType)) {
308                                         // ith param of bestMatch is wider than that of candidate
309                                         if (isBetter == -2) {
310                                                 isBetter = 1;
311                                                 continue;
312                                         } else if (isBetter != 1) {
313                                                 isBetter = -1;
314                                                 continue;
315                                         }
316                                         isBetter = 1;
317                                 }
318                         }
319
320                         if (isBetter == -2) {
321                                 // corresponding parameters of both methods have same types
322                                 // the method having max no of fixed parameters is better
323                                 if (paramArrayIndex1 == -1 && paramArrayIndex2 != -1)
324                                                 return 0;
325                                 if (paramArrayIndex1 != -1 && paramArrayIndex2 == -1)
326                                                 return 1;
327                                 return ((paramArrayIndex1 < paramArrayIndex2) ? 1 : 0);
328                         }
329
330                         return isBetter;
331                 }
332
333                 internal static bool UsesParamArray (ParameterInfo [] pars) {
334                         if (pars == null || pars.Length == 0)
335                                 return false;
336                         ParameterInfo lastParam = pars [pars.GetUpperBound (0)];
337                         object[] attrs = lastParam.GetCustomAttributes (typeof (System.ParamArrayAttribute), false);
338                         if (attrs == null || attrs.Length == 0)
339                                 return false;
340                         return true;
341                 }
342
343                 /*
344                   Gets the number of parameters that are neither optional not ParamArray
345                 */
346                 internal static int CountStandardParams (ParameterInfo [] pars) {
347                         if (pars.Length == 0)
348                                 return 0;
349                         int count = pars.Length;
350                         for (int index = 0; index < pars.Length; index ++) {
351                                 ParameterInfo param = pars [index];
352                                 if (param.IsOptional)
353                                         return index;
354                                 if (index + 1 == pars.Length) {
355                                         object[] attrs = param.GetCustomAttributes (typeof (System.ParamArrayAttribute), false);
356                                         if (attrs != null && attrs.Length > 0)
357                                                 return index;
358                                 }
359                         }
360                         return count;
361                 }
362
363                 private ConversionType GetConversionType (ParameterInfo[] parameters, object[] args) {
364                         int numParams = parameters.Length;
365                         int numArgs = args.Length;
366                         int paramArrayIndex = -1;
367                         int numFixedParams = CountStandardParams (parameters);
368
369                         if (numParams == 0) {
370                                 if (numArgs == 0)
371                                         return ConversionType.Exact;
372                                 else
373                                         return ConversionType.None;
374                         }
375
376                         bool usesParamArray = UsesParamArray (parameters);
377                         if (numFixedParams == 0 && numArgs == 0)
378                                 return ConversionType.Exact;
379
380                         if (numArgs < numFixedParams)
381                                 return ConversionType.None;
382
383                         ConversionType ctype = ConversionType.None;
384                         bool isLastParam = false;
385                         int paramIndex = 0;
386                         for (int index = 0; index < numArgs; index ++) {
387                                 if (index < numFixedParams)
388                                         paramIndex = index;
389                                 else if (usesParamArray) {
390                                         paramIndex = parameters.GetUpperBound (0);
391                                         isLastParam = true;
392                                 }
393
394                                 ConversionType currentCType = ConversionType.None;
395                                 Type type1 = null;
396                                 if (args [index] != null)
397                                         type1 = args [index].GetType ();
398                                 Type type2 = parameters [paramIndex].ParameterType;
399                                 if (type2.IsByRef)
400                                         type2 = type2.GetElementType ();
401                                 if (usesParamArray && isLastParam) {
402                                         if (type1.IsArray) {
403                                                 if (type1.GetElementType () == type2.GetElementType ())
404                                                         currentCType = ConversionType.Exact;
405                                                 else if (ObjectType.IsWideningConversion (type1, type2))
406                                                         currentCType = ConversionType.Widening;
407                                                 else 
408                                                         currentCType = ConversionType.Narrowing;
409                                         } else {
410                                                 Type elementType = type2.GetElementType ();
411                                                 if (type1 == elementType)
412                                                         currentCType = ConversionType.Exact;
413                                                 else if (ObjectType.IsWideningConversion (type1, elementType))
414                                                         currentCType = ConversionType.Widening;
415                                                 else 
416                                                         currentCType = ConversionType.Narrowing;
417                                         }
418                                         if (currentCType == ConversionType.Narrowing || ctype < currentCType)
419                                                 ctype = currentCType;
420
421                                 } else {
422                                         if (type1 == type2) {
423                                                 currentCType = ConversionType.Exact;
424                                                 if (ctype < currentCType) {
425                                                         ctype = ConversionType.Exact;
426                                                 }
427                                         } else if (ObjectType.IsWideningConversion (type1, type2)) {
428                                                 currentCType = ConversionType.Widening;
429                                                 if (ctype < currentCType)
430                                                         ctype = ConversionType.Widening;
431                                         } else 
432                                                 ctype = ConversionType.Narrowing;
433                                 }
434                         }
435
436                         return ctype;
437                 }
438
439                 public override object ChangeType(
440                         object value,
441                         Type myChangeType,
442                         CultureInfo culture
443                         )
444                 {               
445                         TypeCode src_type = Type.GetTypeCode (value.GetType());                 
446                         TypeCode dest_type = Type.GetTypeCode (myChangeType);
447                         
448                         switch (dest_type) {
449                                 case TypeCode.String:
450                                         switch (src_type) {
451                                                 case TypeCode.SByte:                                            
452                                                 case TypeCode.Byte:
453                                                         return (StringType.FromByte ((byte)value));
454                                                 case TypeCode.UInt16:
455                                                 case TypeCode.Int16:
456                                                         return (StringType.FromShort ((short)value));   
457                                                 case TypeCode.UInt32:                                   
458                                                 case TypeCode.Int32:
459                                                         return (StringType.FromInteger ((int)value));                                           
460                                                 case TypeCode.UInt64:   
461                                                 case TypeCode.Int64:
462                                                         return (StringType.FromLong ((long)value));                                             
463                                                 case TypeCode.Char:
464                                                         return (StringType.FromChar ((char)value));                                                     
465                                                 case TypeCode.Single:
466                                                         return (StringType.FromSingle ((float)value));  
467                                                 case TypeCode.Double:
468                                                         return (StringType.FromDouble ((double)value));                                                                                                                                         
469                                                 case TypeCode.Boolean:
470                                                         return (StringType.FromBoolean ((bool)value));  
471                                                 case TypeCode.Object:
472                                                         return (StringType.FromObject (value));                                                                                                                                                                                                                         
473                                         }
474                                         break;
475                                         
476                                 case TypeCode.Int32:
477                                 case TypeCode.UInt32:   
478                                         switch (src_type) {                                             
479                                                 case TypeCode.String:                           
480                                                         return (IntegerType.FromString ((string)value));        
481                                                 case TypeCode.Object:                           
482                                                         return (IntegerType.FromObject (value));                                                                                
483                                         }
484                                         break;  
485
486                                 case TypeCode.Int16:
487                                 case TypeCode.UInt16:   
488                                         switch (src_type) {                                             
489                                                 case TypeCode.String:                           
490                                                         return (ShortType.FromString ((string)value));          
491                                                 case TypeCode.Object:                           
492                                                         return (ShortType.FromObject (value));                                                                          
493                                         }
494                                         break;  
495                                 case TypeCode.Object:
496                                         return ((Object) value);                                                                                                
497                         }
498                         return null;
499                 }
500
501                 public override void ReorderArgumentArray(
502                         ref object[] args,
503                         object state
504                         )
505                 {
506
507                 }
508
509                 public override MethodBase SelectMethod(
510                         BindingFlags bindingAttr,
511                         MethodBase[] match,
512                         Type[] types,
513                         ParameterModifier[] modifiers
514                         )
515                 {
516                         return null;
517                 }
518
519                 public override PropertyInfo SelectProperty(
520                         BindingFlags bindingAttr,
521                         PropertyInfo[] match,
522                         Type returnType,
523                         Type[] indexes,
524                         ParameterModifier[] modifiers
525                         )               
526                 {
527                         return null;
528                 }
529                 
530                 public Object InvokeMember (string name, 
531                                             BindingFlags flags,
532                                             Type objType,
533                                             IReflect objReflect,
534                                             object target,
535                                             object[] args,
536                                             ParameterModifier[] modifiers,
537                                             CultureInfo culture,
538                                             string[] paramNames) {
539
540                         this.objectType = objType;
541                         this.bindToName = name;
542                         if (name == null || name.Equals ("")) {
543                                 // Must be a default property
544                                 Type t = objType;
545                                 while (t != null) {
546                                         object[] attrArray = t.GetCustomAttributes (typeof (DefaultMemberAttribute), false);
547                                         if (attrArray != null && attrArray.Length != 0) {
548                                                 name = ((DefaultMemberAttribute) attrArray[0]).MemberName;
549                                                 break;
550                                         }
551                                         // not found, search in the base type
552                                         t = t.BaseType;
553                                 }
554                         }
555
556                         if (name == null || name.Equals ("")) {
557                                 throw new MissingMemberException ("No default members defined for type '" + objType + "'");
558                         }
559
560                         MemberInfo[] memberinfo = GetMembers (objReflect, objType, name, flags);
561
562                         if (memberinfo == null || memberinfo.Length == 0) {
563                                 throw new MissingMemberException ("No member '" + name + "' defined for type '" + objType + "'");
564                         }
565                         
566                         object objState = null;
567                         object retVal = null;
568                         if (memberinfo [0] is MethodBase) {
569                                 MethodBase[] methodbase = new MethodBase [memberinfo.Length];
570                                 for (int index = 0; index < memberinfo.Length; index ++)
571                                         methodbase [index] = (MethodBase) memberinfo [index];
572                                 MethodBase mbase = BindToMethod (flags, methodbase, ref args, modifiers, culture, paramNames, out objState);
573                                 if (mbase == null) {
574                                         throw new MissingMemberException ("No member '" + name + "' defined for type '" + objType + "' which takes the given set of arguments");
575                                 }
576
577                                 object [] newArgs = args;
578                                 if (objState != null)
579                                         newArgs = ((BinderState) objState).args;
580
581                                 MethodInfo mi = (MethodInfo) mbase;
582                                 retVal =  mi.Invoke (target, newArgs);
583                                 Array.Copy (newArgs, args, args.Length);
584                         }
585
586                         if (objState != null && ((BinderState)objState).byRefFlags != null) {
587                                 this.byRefFlags = ((BinderState)objState).byRefFlags; 
588                         }
589
590                         return retVal;
591                 }
592
593                 /*
594                  Determines whether a given method can be invoked with a given set of arguments
595                 */
596                 private bool IsApplicable (MethodBase mb, object [] args) {
597                         ParameterInfo [] parameters = mb.GetParameters ();
598                         int numFixedParams = CountStandardParams (parameters);
599                         int numParams = parameters.Length;
600                         int argCount = 0;
601                         if (args != null)
602                                 argCount = args.Length;
603
604                         if (numParams == numFixedParams)        // No ParamArray or Optional params
605                                 if (argCount != numParams)
606                                         return false;
607                         
608                         if (argCount < numFixedParams)
609                                 return false;
610
611                         bool usesParamArray = UsesParamArray (parameters);
612                         if (!usesParamArray && (argCount > numParams))
613                                 return false;
614
615                         int paramIndex = 0;
616                         bool isLastParam = false;
617                         for (int index = 0; index < argCount; index ++) {
618                                 Type argType = null;
619                                 Type paramType = null;
620                                 isLastParam = false;
621                                 if (index < numFixedParams) 
622                                         paramIndex = index;
623                                 else if (usesParamArray) {
624                                         paramIndex = numParams - 1;
625                                         isLastParam = true;
626                                 }
627
628                                 paramType = parameters [paramIndex].ParameterType;
629                                 if (args [index] != null) {
630                                         argType = args [index].GetType ();
631                                         if (usesParamArray && isLastParam) {
632                                                 // ParamArray parameter of type 'T'. We can either have an 
633                                                 // argument which is an array of type T, or 'n' number of 
634                                                 // arguments that are of/convertible to type 'T'
635                                                 if (!argType.IsArray) {
636                                                         Type elementType = paramType.GetElementType ();
637                                                         if (!ObjectType.ImplicitConversionExists (argType, elementType))
638                                                                 return false;
639                                                 } else {
640                                                         Type elementType = paramType.GetElementType ();
641                                                         argType = argType.GetElementType ();
642                                                         if (!elementType.IsAssignableFrom (argType))
643                                                                 return false;
644                                                 }
645                                         } else {
646                                                 if (paramType.IsByRef)
647                                                         paramType = paramType.GetElementType ();
648                                                 if (!ObjectType.ImplicitConversionExists (argType, paramType))
649                                                         return false;
650                                         }
651         
652                                 }
653                         }
654                         return true;
655                 }
656
657                 private static MemberInfo [] GetMostDerivedMembers (ArrayList memberinfo) {
658                         int i = 0;
659                         int numElementsEliminated = 0;
660                         for (i = 0; i < memberinfo.Count; i++) {
661                                 MemberInfo mi = (MemberInfo) memberinfo [i];
662                                 for (int j = i + 1; j < memberinfo.Count; j++) {
663                                         bool eliminateBaseMembers = false;
664                                         MemberInfo thisMember = (MemberInfo) memberinfo [j];
665                                         Type t1 = mi.DeclaringType;
666                                         Type t2 = thisMember.DeclaringType;
667                                         if (mi.MemberType == MemberTypes.Field)
668                                                 eliminateBaseMembers = true;
669                                         if (mi.MemberType == MemberTypes.Method) {
670                                                 MethodInfo methodinfo = (MethodInfo) mi;
671                                                 if (methodinfo.IsVirtual)
672                                                         eliminateBaseMembers = true;
673                                         }
674                                         if (mi.MemberType == MemberTypes.Property) {
675                                                 PropertyInfo propertyinfo = (PropertyInfo) mi;
676                                                 MethodInfo method = propertyinfo.GetGetMethod ();
677                                                 if (method.IsVirtual)
678                                                         eliminateBaseMembers = true;
679                                         }
680                                         if (eliminateBaseMembers) {
681                                                 if (t1.IsSubclassOf (t2)) {
682                                                         memberinfo [j] = null;
683                                                         numElementsEliminated ++;
684                                                 } else if (t2.IsSubclassOf (t1)) {
685                                                         memberinfo [i] = null;
686                                                         numElementsEliminated ++;
687                                                 }
688                                         }
689                                 }
690                         }
691
692                         MemberInfo [] newMemberList = new MemberInfo [memberinfo.Count - numElementsEliminated];
693                         int newIndex = 0;
694                         for (int index = 0; index < memberinfo.Count; index ++) {
695                                 if (memberinfo [index] != null) {
696                                         newMemberList [newIndex ++] = (MemberInfo) memberinfo [index];
697                                 }
698                         }
699                         return newMemberList;
700                 }
701
702                 internal MemberInfo [] GetMembers (IReflect objReflect, Type objType, string name, BindingFlags invokeFlags) 
703                 {
704                         MemberInfo [] mi = objReflect.GetMember (name, invokeFlags);
705                         if (mi == null || mi.Length == 0)
706                                 return null;
707
708                         for (int index = 0; index < mi.Length; index ++)
709                         {
710                                 if (mi [index].MemberType == MemberTypes.Property) {
711                                         PropertyInfo propinfo = (PropertyInfo) mi [index];
712                                         if ((invokeFlags & BindingFlags.GetProperty) == BindingFlags.GetProperty) 
713                                                 mi [index] = propinfo.GetGetMethod ();
714                                         else if ((invokeFlags & BindingFlags.SetProperty) == BindingFlags.SetProperty)
715                                                 mi [index] = propinfo.GetSetMethod ();
716                                 }
717                         }
718                         return mi;
719                 }
720         }
721 }