1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 ////////////////////////////////////////////////////////////////////////////////
7 ////////////////////////////////////////////////////////////////////////////////
8 //
9 // This class represents the Default COM+ binder.
10 //
11 //
12 
13 //  Copied from https://github.com/Microsoft/referencesource/blob/74706335e3b8c806f44fa0683dc1e18d3ed747c2/mscorlib/system/defaultbinder.cs
14 
15 namespace System {
16 
17     using System;
18     using System.Reflection;
19     using System.Runtime.CompilerServices;
20     using System.Runtime.Versioning;
21     using System.Diagnostics.Contracts;
22     using CultureInfo = System.Globalization.CultureInfo;
23     //Marked serializable even though it has no state.
24     [Serializable]
25     internal class DefaultBinder //: Binder
26     {
27         // This method is passed a set of methods and must choose the best
28         // fit.  The methods all have the same number of arguments and the object
29         // array args.  On exit, this method will choice the best fit method
30         // and coerce the args to match that method.  By match, we mean all primitive
31         // arguments are exact matchs and all object arguments are exact or subclasses
32         // of the target.  If the target OR is an interface, the object must implement
33         // that interface.  There are a couple of exceptions
34         // thrown when a method cannot be returned.  If no method matchs the args and
35         // ArgumentException is thrown.  If multiple methods match the args then
36         // an AmbiguousMatchException is thrown.
37         //
38         // The most specific match will be selected.
39         //
40         [System.Security.SecuritySafeCritical]  // auto-generated
BindToMethod( BindingFlags bindingAttr, MethodBase[] match, ref Object[] args, ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, out Object state)41         public static MethodBase BindToMethod(
42             BindingFlags bindingAttr, MethodBase[] match, ref Object[] args,
43             ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, out Object state)
44         {
45             if (match == null || match.Length == 0)
46                 throw new ArgumentException("Arg_EmptyArray", "match");
47             Contract.EndContractBlock();
48 
49             MethodBase[] candidates = (MethodBase[]) match.Clone();
50 
51             int i;
52             int j;
53 
54             state = null;
55 
56             #region Map named parameters to candidate parameter postions
57             // We are creating an paramOrder array to act as a mapping
58             //  between the order of the args and the actual order of the
59             //  parameters in the method.  This order may differ because
60             //  named parameters (names) may change the order.  If names
61             //  is not provided, then we assume the default mapping (0,1,...)
62             int[][] paramOrder = new int[candidates.Length][];
63 
64             for (i = 0; i < candidates.Length; i++)
65             {
66                 ParameterInfo[] par = candidates[i].GetParameters();
67 
68                 // args.Length + 1 takes into account the possibility of a last paramArray that can be omitted
69                 paramOrder[i] = new int[(par.Length > args.Length) ? par.Length : args.Length];
70 
71                 if (names == null)
72                 {
73                     // Default mapping
74                     for (j = 0; j < args.Length; j++)
75                         paramOrder[i][j] = j;
76                 }
77                 else
78                 {
79                     // Named parameters, reorder the mapping.  If CreateParamOrder fails, it means that the method
80                     // doesn't have a name that matchs one of the named parameters so we don't consider it any further.
81                      if (!CreateParamOrder(paramOrder[i], par, names))
82                          candidates[i] = null;
83                 }
84             }
85             #endregion
86 
87             Type[] paramArrayTypes = new Type[candidates.Length];
88 
89             Type[] argTypes = new Type[args.Length];
90 
91             #region Cache the type of the provided arguments
92             // object that contain a null are treated as if they were typeless (but match either object
93             // references or value classes).  We mark this condition by placing a null in the argTypes array.
94             for (i = 0; i < args.Length; i++)
95             {
96                 if (args[i] != null)
97                 {
98                     argTypes[i] = args[i].GetType();
99                 }
100             }
101             #endregion
102 
103 
104             // Find the method that matches...
105             int CurIdx = 0;
106             //bool defaultValueBinding = ((bindingAttr & BindingFlags.OptionalParamBinding) != 0);
107             bool defaultValueBinding = false;
108 
109             Type paramArrayType = null;
110 
111             #region Filter methods by parameter count and type
112             for (i = 0; i < candidates.Length; i++)
113             {
114                 paramArrayType = null;
115 
116                 // If we have named parameters then we may have a hole in the candidates array.
117                 if (candidates[i] == null)
118                     continue;
119 
120                 // Validate the parameters.
121                 ParameterInfo[] par = candidates[i].GetParameters();
122 
123                 #region Match method by parameter count
124                 if (par.Length == 0)
125                 {
126                     #region No formal parameters
127                     if (args.Length != 0)
128                     {
129                         if ((candidates[i].CallingConvention & CallingConventions.VarArgs) == 0)
130                             continue;
131                     }
132 
133                     // This is a valid routine so we move it up the candidates list.
134                     paramOrder[CurIdx] = paramOrder[i];
135                     candidates[CurIdx++] = candidates[i];
136 
137                     continue;
138                     #endregion
139                 }
140                 else if (par.Length > args.Length)
141                 {
142                     #region Shortage of provided parameters
143                     // If the number of parameters is greater than the number of args then
144                     // we are in the situation were we may be using default values.
145                     for (j = args.Length; j < par.Length - 1; j++)
146                     {
147                         //if (par[j].DefaultValue == System.DBNull.Value)
148                         if (!par[j].HasDefaultValue)
149                            break;
150                     }
151 
152                     if (j != par.Length - 1)
153                         continue;
154 
155                     //if (par[j].DefaultValue == System.DBNull.Value)
156                     if (!par[j].HasDefaultValue)
157                     {
158                         if (!par[j].ParameterType.IsArray)
159                             continue;
160 
161                         if (!par[j].IsDefined(typeof(ParamArrayAttribute), true))
162                             continue;
163 
164                         paramArrayType = par[j].ParameterType.GetElementType();
165                     }
166                     #endregion
167                 }
168                 else if (par.Length < args.Length)
169                 {
170                     #region Excess provided parameters
171                     // test for the ParamArray case
172                     int lastArgPos = par.Length - 1;
173 
174                     if (!par[lastArgPos].ParameterType.IsArray)
175                         continue;
176 
177                     if (!par[lastArgPos].IsDefined(typeof(ParamArrayAttribute), true))
178                         continue;
179 
180                     if (paramOrder[i][lastArgPos] != lastArgPos)
181                         continue;
182 
183                     paramArrayType = par[lastArgPos].ParameterType.GetElementType();
184                     #endregion
185                 }
186                 else
187                 {
188                     #region Test for paramArray, save paramArray type
189                     int lastArgPos = par.Length - 1;
190 
191                     if (par[lastArgPos].ParameterType.IsArray
192                         && par[lastArgPos].IsDefined(typeof(ParamArrayAttribute), true)
193                         && paramOrder[i][lastArgPos] == lastArgPos)
194                     {
195                         if (!par[lastArgPos].ParameterType.IsAssignableFrom(argTypes[lastArgPos]))
196                             paramArrayType = par[lastArgPos].ParameterType.GetElementType();
197                     }
198                     #endregion
199                 }
200                 #endregion
201 
202                 Type pCls = null;
203                 int argsToCheck = (paramArrayType != null) ? par.Length - 1 : args.Length;
204 
205                 #region Match method by parameter type
206                 for (j = 0; j < argsToCheck; j++)
207                 {
208                     #region Classic argument coersion checks
209                     // get the formal type
210                     pCls = par[j].ParameterType;
211 
212                     if (pCls.IsByRef)
213                         pCls = pCls.GetElementType();
214 
215                     // the type is the same
216                     if (pCls == argTypes[paramOrder[i][j]])
217                         continue;
218 
219                     // a default value is available
220                     if (defaultValueBinding && args[paramOrder[i][j]] == Type.Missing)
221                         continue;
222 
223                     // the argument was null, so it matches with everything
224                     if (args[paramOrder[i][j]] == null)
225                         continue;
226 
227                     // the type is Object, so it will match everything
228                     if (pCls == typeof(Object))
229                         continue;
230 
231                     // now do a "classic" type check
232                     if (pCls.GetTypeInfo().IsPrimitive)
233                     {
234                         if (argTypes[paramOrder[i][j]] == null || !CanConvertPrimitiveObjectToType(args[paramOrder[i][j]],pCls))
235                         {
236 #if !FEATURE_COMINTEROP && false
237                             if (CanChangeType(args[paramOrder[i][j]],pCls,cultureInfo))
238                                 continue;
239 #endif
240                             break;
241                         }
242                     }
243                     else
244                     {
245                         if (argTypes[paramOrder[i][j]] == null)
246                             continue;
247 
248                         if (!pCls.IsAssignableFrom(argTypes[paramOrder[i][j]]))
249                         {
250 #if false
251                             if (argTypes[paramOrder[i][j]].IsCOMObject)
252                             {
253                                 if (pCls.IsInstanceOfType(args[paramOrder[i][j]]))
254                                     continue;
255                             }
256 #endif
257 #if !FEATURE_COMINTEROP && false
258                             if (CanChangeType(args[paramOrder[i][j]],pCls,cultureInfo))
259                                 continue;
260 #endif
261                             break;
262                         }
263                     }
264 #endregion
265                 }
266 
267                 if (paramArrayType != null && j == par.Length - 1)
268                 {
269 #region Check that excess arguments can be placed in the param array
270                     for (; j < args.Length; j++)
271                     {
272                         if (paramArrayType.GetTypeInfo().IsPrimitive)
273                         {
274                             if (argTypes[j] == null || !CanConvertPrimitiveObjectToType(args[j], paramArrayType))
275                                 break;
276                         }
277                         else
278                         {
279                             if (argTypes[j] == null)
280                                 continue;
281 
282                             if (!paramArrayType.IsAssignableFrom(argTypes[j]))
283                             {
284 #if false
285                                 if (argTypes[j].IsCOMObject)
286                                 {
287                                     if (paramArrayType.IsInstanceOfType(args[j]))
288                                         continue;
289                                 }
290 #endif
291 
292                                 break;
293                             }
294                         }
295                     }
296 #endregion
297                 }
298 #endregion
299 
300                 if (j == args.Length)
301                 {
302 #region This is a valid routine so we move it up the candidates list
303                     paramOrder[CurIdx] = paramOrder[i];
304                     paramArrayTypes[CurIdx] = paramArrayType;
305                     candidates[CurIdx++] = candidates[i];
306 #endregion
307                 }
308             }
309 #endregion
310 
311             // If we didn't find a method
312             if (CurIdx == 0)
313                 throw new MissingMethodException("MissingMember");
314 
315             if (CurIdx == 1)
316             {
317 #region Found only one method
318                 if (names != null)
319                 {
320                     state = new BinderState((int[])paramOrder[0].Clone(), args.Length, paramArrayTypes[0] != null);
321                     ReorderParams(paramOrder[0],args);
322                 }
323 
324                 // If the parameters and the args are not the same length or there is a paramArray
325                 //  then we need to create a argument array.
326                 ParameterInfo[] parms = candidates[0].GetParameters();
327 
328                 if (parms.Length == args.Length)
329                 {
330                     if (paramArrayTypes[0] != null)
331                     {
332                         Object[] objs = new Object[parms.Length];
333                         int lastPos = parms.Length - 1;
334                         Array.Copy(args, 0, objs, 0, lastPos);
335                         objs[lastPos] = Array.CreateInstance(paramArrayTypes[0], 1);
336                         ((Array)objs[lastPos]).SetValue(args[lastPos], 0);
337                         args = objs;
338                     }
339                 }
340                 else if (parms.Length > args.Length)
341                 {
342                     Object[] objs = new Object[parms.Length];
343 
344                     for (i=0;i<args.Length;i++)
345                         objs[i] = args[i];
346 
347                     for (;i<parms.Length - 1;i++)
348                         objs[i] = parms[i].DefaultValue;
349 
350                     if (paramArrayTypes[0] != null)
351                         objs[i] = Array.CreateInstance(paramArrayTypes[0], 0); // create an empty array for the
352 
353                     else
354                         objs[i] = parms[i].DefaultValue;
355 
356                     args = objs;
357                 }
358                 else
359                 {
360                     if ((candidates[0].CallingConvention & CallingConventions.VarArgs) == 0)
361                     {
362                         Object[] objs = new Object[parms.Length];
363                         int paramArrayPos = parms.Length - 1;
364                         Array.Copy(args, 0, objs, 0, paramArrayPos);
365                         objs[paramArrayPos] = Array.CreateInstance(paramArrayTypes[0], args.Length - paramArrayPos);
366                         Array.Copy(args, paramArrayPos, (System.Array)objs[paramArrayPos], 0, args.Length - paramArrayPos);
367                         args = objs;
368                     }
369                 }
370 #endregion
371 
372                 return candidates[0];
373             }
374 
375             int currentMin = 0;
376             bool ambig = false;
377             for (i = 1; i < CurIdx; i++)
378             {
379 #region Walk all of the methods looking the most specific method to invoke
380                 int newMin = FindMostSpecificMethod(candidates[currentMin], paramOrder[currentMin], paramArrayTypes[currentMin],
381                                                     candidates[i], paramOrder[i], paramArrayTypes[i], argTypes, args);
382 
383                 if (newMin == 0)
384                 {
385                     ambig = true;
386                 }
387                 else  if (newMin == 2)
388                 {
389                     currentMin = i;
390                     ambig = false;
391                 }
392 #endregion
393             }
394 
395             if (ambig)
396                 throw new AmbiguousMatchException("Arg_AmbiguousMatchException");
397 
398             // Reorder (if needed)
399             if (names != null) {
400                 state = new BinderState((int[])paramOrder[currentMin].Clone(), args.Length, paramArrayTypes[currentMin] != null);
401                 ReorderParams(paramOrder[currentMin], args);
402             }
403 
404             // If the parameters and the args are not the same length or there is a paramArray
405             //  then we need to create a argument array.
406             ParameterInfo[] parameters = candidates[currentMin].GetParameters();
407             if (parameters.Length == args.Length)
408             {
409                 if (paramArrayTypes[currentMin] != null)
410                 {
411                     Object[] objs = new Object[parameters.Length];
412                     int lastPos = parameters.Length - 1;
413                     Array.Copy(args, 0, objs, 0, lastPos);
414                     objs[lastPos] = Array.CreateInstance(paramArrayTypes[currentMin], 1);
415                     ((Array)objs[lastPos]).SetValue(args[lastPos], 0);
416                     args = objs;
417                 }
418             }
419             else if (parameters.Length > args.Length)
420             {
421                 Object[] objs = new Object[parameters.Length];
422 
423                 for (i=0;i<args.Length;i++)
424                     objs[i] = args[i];
425 
426                 for (;i<parameters.Length - 1;i++)
427                     objs[i] = parameters[i].DefaultValue;
428 
429                 if (paramArrayTypes[currentMin] != null)
430                 {
431                     objs[i] = Array.CreateInstance(paramArrayTypes[currentMin], 0);
432                 }
433                 else
434                 {
435                     objs[i] = parameters[i].DefaultValue;
436                 }
437 
438                 args = objs;
439             }
440             else
441             {
442                 if ((candidates[currentMin].CallingConvention & CallingConventions.VarArgs) == 0)
443                 {
444                     Object[] objs = new Object[parameters.Length];
445                     int paramArrayPos = parameters.Length - 1;
446                     Array.Copy(args, 0, objs, 0, paramArrayPos);
447                     objs[paramArrayPos] = Array.CreateInstance(paramArrayTypes[currentMin], args.Length - paramArrayPos);
448                     Array.Copy(args, paramArrayPos, (System.Array)objs[paramArrayPos], 0, args.Length - paramArrayPos);
449                     args = objs;
450                 }
451             }
452 
453             return candidates[currentMin];
454         }
455 
456 #if false
457         // Given a set of fields that match the base criteria, select a field.
458         // if value is null then we have no way to select a field
459         [System.Security.SecuritySafeCritical]  // auto-generated
BindToField(BindingFlags bindingAttr,FieldInfo[] match, Object value,CultureInfo cultureInfo)460         public override FieldInfo BindToField(BindingFlags bindingAttr,FieldInfo[] match, Object value,CultureInfo cultureInfo)
461         {
462             if (match == null) {
463                 throw new ArgumentNullException("match");
464             }
465 
466             int i;
467             // Find the method that match...
468             int CurIdx = 0;
469 
470             Type valueType = null;
471 
472             FieldInfo[] candidates = (FieldInfo[]) match.Clone();
473 
474             // If we are a FieldSet, then use the value's type to disambiguate
475             if ((bindingAttr & BindingFlags.SetField) != 0) {
476                 valueType = value.GetType();
477 
478                 for (i=0;i<candidates.Length;i++) {
479                     Type pCls = candidates[i].FieldType;
480                     if (pCls == valueType) {
481                         candidates[CurIdx++] = candidates[i];
482                         continue;
483                     }
484                     if (value == Empty.Value) {
485                         // the object passed in was null which would match any non primitive non value type
486                         if (pCls.IsClass) {
487                             candidates[CurIdx++] = candidates[i];
488                             continue;
489                         }
490                     }
491                     if (pCls == typeof(Object)) {
492                         candidates[CurIdx++] = candidates[i];
493                         continue;
494                     }
495                     if (pCls.IsPrimitive) {
496                         if (CanConvertPrimitiveObjectToType(value,(RuntimeType)pCls)) {
497                             candidates[CurIdx++] = candidates[i];
498                             continue;
499                         }
500                     }
501                     else {
502                         if (pCls.IsAssignableFrom(valueType)) {
503                             candidates[CurIdx++] = candidates[i];
504                             continue;
505                         }
506                     }
507                 }
508                 if (CurIdx == 0)
509                     throw new MissingFieldException(Environment.GetResourceString("MissingField"));
510                 if (CurIdx == 1)
511                     return candidates[0];
512             }
513 
514             // Walk all of the methods looking the most specific method to invoke
515             int currentMin = 0;
516             bool ambig = false;
517             for (i=1;i<CurIdx;i++) {
518                 int newMin = FindMostSpecificField(candidates[currentMin], candidates[i]);
519                 if (newMin == 0)
520                     ambig = true;
521                 else {
522                     if (newMin == 2) {
523                         currentMin = i;
524                         ambig = false;
525                     }
526                 }
527             }
528             if (ambig)
529                 throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
530             return candidates[currentMin];
531         }
532 #endif
533 
534         // Given a set of methods that match the base criteria, select a method based
535         // upon an array of types.  This method should return null if no method matchs
536         // the criteria.
537         [System.Security.SecuritySafeCritical]  // auto-generated
SelectMethod(BindingFlags bindingAttr,MethodBase[] match,Type[] types,ParameterModifier[] modifiers)538         public static MethodBase SelectMethod(BindingFlags bindingAttr,MethodBase[] match,Type[] types,ParameterModifier[] modifiers)
539         {
540             int i;
541             int j;
542 
543             //Type[] realTypes = new Type[types.Length];
544             //for (i=0;i<types.Length;i++) {
545             //    realTypes[i] = types[i].UnderlyingSystemType;
546             //    if (!(realTypes[i] is RuntimeType))
547             //        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"),"types");
548             //}
549             //types = realTypes;
550 
551             // We don't automatically jump out on exact match.
552             if (match == null || match.Length == 0)
553                 throw new ArgumentException("Arg_EmptyArray", "match");
554 
555             MethodBase[] candidates = (MethodBase[]) match.Clone();
556 
557             // Find all the methods that can be described by the types parameter.
558             //  Remove all of them that cannot.
559             int CurIdx = 0;
560             for (i=0;i<candidates.Length;i++) {
561                 ParameterInfo[] par = candidates[i].GetParameters();
562                 if (par.Length != types.Length)
563                     continue;
564                 for (j=0;j<types.Length;j++) {
565                     Type pCls = par[j].ParameterType;
566                     if (pCls == types[j])
567                         continue;
568                     if (pCls == typeof(Object))
569                         continue;
570                     if (pCls.GetTypeInfo().IsPrimitive) {
571                         //if (!(types[j].UnderlyingSystemType is RuntimeType) ||
572                         //    !CanConvertPrimitive((RuntimeType)types[j].UnderlyingSystemType,(RuntimeType)pCls.UnderlyingSystemType))
573                         if (!CanConvertPrimitive(types[j], pCls))
574                             break;
575                     }
576                     else {
577                         if (!pCls.IsAssignableFrom(types[j]))
578                             break;
579                     }
580                 }
581                 if (j == types.Length)
582                     candidates[CurIdx++] = candidates[i];
583             }
584             if (CurIdx == 0)
585                 return null;
586             if (CurIdx == 1)
587                 return candidates[0];
588 
589             // Walk all of the methods looking the most specific method to invoke
590             int currentMin = 0;
591             bool ambig = false;
592             int[] paramOrder = new int[types.Length];
593             for (i=0;i<types.Length;i++)
594                 paramOrder[i] = i;
595             for (i=1;i<CurIdx;i++) {
596                 int newMin = FindMostSpecificMethod(candidates[currentMin], paramOrder, null, candidates[i], paramOrder, null, types, null);
597                 if (newMin == 0)
598                     ambig = true;
599                 else {
600                     if (newMin == 2) {
601                         currentMin = i;
602                         ambig = false;
603                         currentMin = i;
604                     }
605                 }
606             }
607             if (ambig)
608                 throw new AmbiguousMatchException("Arg_AmbiguousMatchException");
609             return candidates[currentMin];
610         }
611 
612 #if false
613         // Given a set of properties that match the base criteria, select one.
614         [System.Security.SecuritySafeCritical]  // auto-generated
SelectProperty(BindingFlags bindingAttr,PropertyInfo[] match,Type returnType, Type[] indexes,ParameterModifier[] modifiers)615         public override PropertyInfo SelectProperty(BindingFlags bindingAttr,PropertyInfo[] match,Type returnType,
616                     Type[] indexes,ParameterModifier[] modifiers)
617         {
618             // Allow a null indexes array. But if it is not null, every element must be non-null as well.
619             if (indexes != null && !Contract.ForAll(indexes, delegate(Type t) { return t != null; }))
620             {
621                 Exception e;  // Written this way to pass the Code Contracts style requirements.
622 #if FEATURE_LEGACYNETCF
623                 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
624                     e = new NullReferenceException();
625                 else
626 #endif
627                     e = new ArgumentNullException("indexes");
628                 throw e;
629             }
630             if (match == null || match.Length == 0)
631                 throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "match");
632             Contract.EndContractBlock();
633 
634             PropertyInfo[] candidates = (PropertyInfo[]) match.Clone();
635 
636             int i,j = 0;
637 
638             // Find all the properties that can be described by type indexes parameter
639             int CurIdx = 0;
640             int indexesLength = (indexes != null) ? indexes.Length : 0;
641             for (i=0;i<candidates.Length;i++) {
642 
643                 if (indexes != null)
644                 {
645                     ParameterInfo[] par = candidates[i].GetIndexParameters();
646                     if (par.Length != indexesLength)
647                         continue;
648 
649                     for (j=0;j<indexesLength;j++) {
650                         Type pCls = par[j]. ParameterType;
651 
652                         // If the classes  exactly match continue
653                         if (pCls == indexes[j])
654                             continue;
655                         if (pCls == typeof(Object))
656                             continue;
657 
658                         if (pCls.IsPrimitive) {
659                             if (!(indexes[j].UnderlyingSystemType is RuntimeType) ||
660                                 !CanConvertPrimitive((RuntimeType)indexes[j].UnderlyingSystemType,(RuntimeType)pCls.UnderlyingSystemType))
661                                 break;
662                         }
663                         else {
664                             if (!pCls.IsAssignableFrom(indexes[j]))
665                                 break;
666                         }
667                     }
668                 }
669 
670                 if (j == indexesLength) {
671                     if (returnType != null) {
672                         if (candidates[i].PropertyType.IsPrimitive) {
673                             if (!(returnType.UnderlyingSystemType is RuntimeType) ||
674                                 !CanConvertPrimitive((RuntimeType)returnType.UnderlyingSystemType,(RuntimeType)candidates[i].PropertyType.UnderlyingSystemType))
675                                 continue;
676                         }
677                         else {
678                             if (!candidates[i].PropertyType.IsAssignableFrom(returnType))
679                                 continue;
680                         }
681                     }
682                     candidates[CurIdx++] = candidates[i];
683                 }
684             }
685             if (CurIdx == 0)
686                 return null;
687             if (CurIdx == 1)
688                 return candidates[0];
689 
690             // Walk all of the properties looking the most specific method to invoke
691             int currentMin = 0;
692             bool ambig = false;
693             int[] paramOrder = new int[indexesLength];
694             for (i=0;i<indexesLength;i++)
695                 paramOrder[i] = i;
696             for (i=1;i<CurIdx;i++) {
697                 int newMin = FindMostSpecificType(candidates[currentMin].PropertyType, candidates[i].PropertyType,returnType);
698                 if (newMin == 0 && indexes != null)
699                     newMin = FindMostSpecific(candidates[currentMin].GetIndexParameters(),
700                                               paramOrder,
701                                               null,
702                                               candidates[i].GetIndexParameters(),
703                                               paramOrder,
704                                               null,
705                                               indexes,
706                                               null);
707                 if (newMin == 0)
708                 {
709                     newMin = FindMostSpecificProperty(candidates[currentMin], candidates[i]);
710                     if (newMin == 0)
711                         ambig = true;
712                 }
713                 if (newMin == 2) {
714                     ambig = false;
715                     currentMin = i;
716                 }
717             }
718 
719             if (ambig)
720                 throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
721             return candidates[currentMin];
722         }
723 
724         // ChangeType
725         // The default binder doesn't support any change type functionality.
726         // This is because the default is built into the low level invoke code.
ChangeType(Object value,Type type,CultureInfo cultureInfo)727         public override Object ChangeType(Object value,Type type,CultureInfo cultureInfo)
728         {
729             throw new NotSupportedException(Environment.GetResourceString("NotSupported_ChangeType"));
730         }
731 #endif
732 
ReorderArgumentArray(ref Object[] args, Object state)733         public static void ReorderArgumentArray(ref Object[] args, Object state)
734         {
735             BinderState binderState = (BinderState)state;
736             ReorderParams(binderState.m_argsMap, args);
737             if (binderState.m_isParamArray) {
738                 int paramArrayPos = args.Length - 1;
739                 if (args.Length == binderState.m_originalSize)
740                     args[paramArrayPos] = ((Object[])args[paramArrayPos])[0];
741                 else {
742                     // must be args.Length < state.originalSize
743                     Object[] newArgs = new Object[args.Length];
744                     Array.Copy(args, 0, newArgs, 0, paramArrayPos);
745                     for (int i = paramArrayPos, j = 0; i < newArgs.Length; i++, j++) {
746                         newArgs[i] = ((Object[])args[paramArrayPos])[j];
747                     }
748                     args = newArgs;
749                 }
750             }
751             else {
752                 if (args.Length > binderState.m_originalSize) {
753                     Object[] newArgs = new Object[binderState.m_originalSize];
754                     Array.Copy(args, 0, newArgs, 0, binderState.m_originalSize);
755                     args = newArgs;
756                 }
757             }
758         }
759 
760 #if false
761         // Return any exact bindings that may exist. (This method is not defined on the
762         //  Binder and is used by RuntimeType.)
ExactBinding(MethodBase[] match,Type[] types,ParameterModifier[] modifiers)763         public static MethodBase ExactBinding(MethodBase[] match,Type[] types,ParameterModifier[] modifiers)
764         {
765             if (match==null)
766                 throw new ArgumentNullException("match");
767             Contract.EndContractBlock();
768             MethodBase[] aExactMatches = new MethodBase[match.Length];
769             int cExactMatches = 0;
770 
771             for (int i=0;i<match.Length;i++) {
772                 ParameterInfo[] par = match[i].GetParametersNoCopy();
773                 if (par.Length == 0) {
774                     continue;
775                 }
776                 int j;
777                 for (j=0;j<types.Length;j++) {
778                     Type pCls = par[j]. ParameterType;
779 
780                     // If the classes  exactly match continue
781                     if (!pCls.Equals(types[j]))
782                         break;
783                 }
784                 if (j < types.Length)
785                     continue;
786 
787                 // Add the exact match to the array of exact matches.
788                 aExactMatches[cExactMatches] = match[i];
789                 cExactMatches++;
790             }
791 
792             if (cExactMatches == 0)
793                 return null;
794 
795             if (cExactMatches == 1)
796                 return aExactMatches[0];
797 
798             return FindMostDerivedNewSlotMeth(aExactMatches, cExactMatches);
799         }
800 
801         // Return any exact bindings that may exist. (This method is not defined on the
802         //  Binder and is used by RuntimeType.)
ExactPropertyBinding(PropertyInfo[] match,Type returnType,Type[] types,ParameterModifier[] modifiers)803         public static PropertyInfo ExactPropertyBinding(PropertyInfo[] match,Type returnType,Type[] types,ParameterModifier[] modifiers)
804         {
805             if (match==null)
806                 throw new ArgumentNullException("match");
807             Contract.EndContractBlock();
808 
809             PropertyInfo bestMatch = null;
810             int typesLength = (types != null) ? types.Length : 0;
811             for (int i=0;i<match.Length;i++) {
812                 ParameterInfo[] par = match[i].GetIndexParameters();
813                 int j;
814                 for (j=0;j<typesLength;j++) {
815                     Type pCls = par[j].ParameterType;
816 
817                     // If the classes  exactly match continue
818                     if (pCls != types[j])
819                         break;
820                 }
821                 if (j < typesLength)
822                     continue;
823                 if (returnType != null && returnType != match[i].PropertyType)
824                     continue;
825 
826                 if (bestMatch != null)
827                     throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
828 
829                 bestMatch = match[i];
830             }
831             return bestMatch;
832         }
833 #endif
834 
FindMostSpecific(ParameterInfo[] p1, int[] paramOrder1, Type paramArrayType1, ParameterInfo[] p2, int[] paramOrder2, Type paramArrayType2, Type[] types, Object[] args)835         private static int FindMostSpecific(ParameterInfo[] p1, int[] paramOrder1, Type paramArrayType1,
836                                             ParameterInfo[] p2, int[] paramOrder2, Type paramArrayType2,
837                                             Type[] types, Object[] args)
838         {
839             // A method using params is always less specific than one not using params
840             if (paramArrayType1 != null && paramArrayType2 == null) return 2;
841             if (paramArrayType2 != null && paramArrayType1 == null) return 1;
842 
843             // now either p1 and p2 both use params or neither does.
844 
845             bool p1Less = false;
846             bool p2Less = false;
847 
848             for (int i = 0; i < types.Length; i++)
849             {
850                 if (args != null && args[i] == Type.Missing)
851                     continue;
852 
853                 Type c1, c2;
854 
855                 //  If a param array is present, then either
856                 //      the user re-ordered the parameters in which case
857                 //          the argument to the param array is either an array
858                 //              in which case the params is conceptually ignored and so paramArrayType1 == null
859                 //          or the argument to the param array is a single element
860                 //              in which case paramOrder[i] == p1.Length - 1 for that element
861                 //      or the user did not re-order the parameters in which case
862                 //          the paramOrder array could contain indexes larger than p.Length - 1 (see VSW 577286)
863                 //          so any index >= p.Length - 1 is being put in the param array
864 
865                 if (paramArrayType1 != null && paramOrder1[i] >= p1.Length - 1)
866                     c1 = paramArrayType1;
867                 else
868                     c1 = p1[paramOrder1[i]].ParameterType;
869 
870                 if (paramArrayType2 != null && paramOrder2[i] >= p2.Length - 1)
871                     c2 = paramArrayType2;
872                 else
873                     c2 = p2[paramOrder2[i]].ParameterType;
874 
875                 if (c1 == c2) continue;
876 
877                 switch (FindMostSpecificType(c1, c2, types[i])) {
878                     case 0: return 0;
879                     case 1: p1Less = true; break;
880                     case 2: p2Less = true; break;
881                 }
882             }
883 
884             // Two way p1Less and p2Less can be equal.  All the arguments are the
885             //  same they both equal false, otherwise there were things that both
886             //  were the most specific type on....
887             if (p1Less == p2Less)
888             {
889                 // if we cannot tell which is a better match based on parameter types (p1Less == p2Less),
890                 // let's see which one has the most matches without using the params array (the longer one wins).
891                 if (!p1Less && args != null)
892                 {
893                     if (p1.Length > p2.Length)
894                     {
895                         return 1;
896                     }
897                     else if (p2.Length > p1.Length)
898                     {
899                         return 2;
900                     }
901                 }
902 
903                 return 0;
904             }
905             else
906             {
907                 return (p1Less == true) ? 1 : 2;
908             }
909         }
910 
911         [System.Security.SecuritySafeCritical]  // auto-generated
FindMostSpecificType(Type c1, Type c2, Type t)912         private static int FindMostSpecificType(Type c1, Type c2, Type t)
913         {
914             // If the two types are exact move on...
915             if (c1 == c2)
916                 return 0;
917 
918             if (c1 == t)
919                 return 1;
920 
921             if (c2 == t)
922                 return 2;
923 
924             bool c1FromC2;
925             bool c2FromC1;
926 
927             if (c1.IsByRef || c2.IsByRef)
928             {
929                 if (c1.IsByRef && c2.IsByRef)
930                 {
931                     c1 = c1.GetElementType();
932                     c2 = c2.GetElementType();
933                 }
934                 else if (c1.IsByRef)
935                 {
936                     if (c1.GetElementType() == c2)
937                         return 2;
938 
939                     c1 = c1.GetElementType();
940                 }
941                 else
942                 {
943                     if (c2.GetElementType() == c1)
944                         return 1;
945 
946                     c2 = c2.GetElementType();
947                 }
948             }
949 
950 #if false
951             if (c1.GetTypeInfo().IsPrimitive && c2.GetTypeInfo().IsPrimitive)
952             {
953                 c1FromC2 = CanConvertPrimitive((RuntimeType)c2, (RuntimeType)c1);
954                 c2FromC1 = CanConvertPrimitive((RuntimeType)c1, (RuntimeType)c2);
955             }
956             else
957 #endif
958             {
959                 c1FromC2 = c1.IsAssignableFrom(c2);
960                 c2FromC1 = c2.IsAssignableFrom(c1);
961             }
962 
963             if (c1FromC2 == c2FromC1)
964                 return 0;
965 
966             if (c1FromC2)
967             {
968                 return 2;
969             }
970             else
971             {
972                 return 1;
973             }
974         }
975 
FindMostSpecificMethod(MethodBase m1, int[] paramOrder1, Type paramArrayType1, MethodBase m2, int[] paramOrder2, Type paramArrayType2, Type[] types, Object[] args)976         private static int FindMostSpecificMethod(MethodBase m1, int[] paramOrder1, Type paramArrayType1,
977                                                   MethodBase m2, int[] paramOrder2, Type paramArrayType2,
978                                                   Type[] types, Object[] args)
979         {
980             // Find the most specific method based on the parameters.
981             int res = FindMostSpecific(m1.GetParameters(), paramOrder1, paramArrayType1,
982                                        m2.GetParameters(), paramOrder2, paramArrayType2, types, args);
983 
984             // If the match was not ambigous then return the result.
985             if (res != 0)
986                 return res;
987 
988             // Check to see if the methods have the exact same name and signature.
989             if (CompareMethodSigAndName(m1, m2))
990             {
991                 // Determine the depth of the declaring types for both methods.
992                 int hierarchyDepth1 = GetHierarchyDepth(m1.DeclaringType);
993                 int hierarchyDepth2 = GetHierarchyDepth(m2.DeclaringType);
994 
995                 // The most derived method is the most specific one.
996                 if (hierarchyDepth1 == hierarchyDepth2)
997                 {
998                     return 0;
999                 }
1000                 else if (hierarchyDepth1 < hierarchyDepth2)
1001                 {
1002                     return 2;
1003                 }
1004                 else
1005                 {
1006                     return 1;
1007                 }
1008             }
1009 
1010             // The match is ambigous.
1011             return 0;
1012         }
1013 
1014 #if false
FindMostSpecificField(FieldInfo cur1,FieldInfo cur2)1015         private static int FindMostSpecificField(FieldInfo cur1,FieldInfo cur2)
1016         {
1017             // Check to see if the fields have the same name.
1018             if (cur1.Name == cur2.Name)
1019             {
1020                 int hierarchyDepth1 = GetHierarchyDepth(cur1.DeclaringType);
1021                 int hierarchyDepth2 = GetHierarchyDepth(cur2.DeclaringType);
1022 
1023                 if (hierarchyDepth1 == hierarchyDepth2) {
1024                     Contract.Assert(cur1.IsStatic != cur2.IsStatic, "hierarchyDepth1 == hierarchyDepth2");
1025                     return 0;
1026                 }
1027                 else if (hierarchyDepth1 < hierarchyDepth2)
1028                     return 2;
1029                 else
1030                     return 1;
1031             }
1032 
1033             // The match is ambigous.
1034             return 0;
1035         }
1036 
FindMostSpecificProperty(PropertyInfo cur1,PropertyInfo cur2)1037         private static int FindMostSpecificProperty(PropertyInfo cur1,PropertyInfo cur2)
1038         {
1039             // Check to see if the fields have the same name.
1040             if (cur1.Name == cur2.Name)
1041             {
1042                 int hierarchyDepth1 = GetHierarchyDepth(cur1.DeclaringType);
1043                 int hierarchyDepth2 = GetHierarchyDepth(cur2.DeclaringType);
1044 
1045                 if (hierarchyDepth1 == hierarchyDepth2) {
1046                     return 0;
1047                 }
1048                 else if (hierarchyDepth1 < hierarchyDepth2)
1049                     return 2;
1050                 else
1051                     return 1;
1052             }
1053 
1054             // The match is ambigous.
1055             return 0;
1056         }
1057 #endif
1058 
CompareMethodSigAndName(MethodBase m1, MethodBase m2)1059         internal static bool CompareMethodSigAndName(MethodBase m1, MethodBase m2)
1060         {
1061             ParameterInfo[] params1 = m1.GetParameters();
1062             ParameterInfo[] params2 = m2.GetParameters();
1063 
1064             if (params1.Length != params2.Length)
1065                 return false;
1066 
1067             int numParams = params1.Length;
1068             for (int i = 0; i < numParams; i++)
1069             {
1070                 if (params1[i].ParameterType != params2[i].ParameterType)
1071                     return false;
1072             }
1073 
1074             return true;
1075         }
1076 
GetHierarchyDepth(Type t)1077         internal static int GetHierarchyDepth(Type t)
1078         {
1079             int depth = 0;
1080 
1081             Type currentType = t;
1082             do
1083             {
1084                 depth++;
1085                 currentType = currentType.GetTypeInfo().BaseType;
1086             } while (currentType != null);
1087 
1088             return depth;
1089         }
1090 
FindMostDerivedNewSlotMeth(MethodBase[] match, int cMatches)1091         internal static MethodBase FindMostDerivedNewSlotMeth(MethodBase[] match, int cMatches)
1092         {
1093             int deepestHierarchy = 0;
1094             MethodBase methWithDeepestHierarchy = null;
1095 
1096             for (int i = 0; i < cMatches; i++)
1097             {
1098                 // Calculate the depth of the hierarchy of the declaring type of the
1099                 // current method.
1100                 int currentHierarchyDepth = GetHierarchyDepth(match[i].DeclaringType);
1101 
1102                 // The two methods have the same name, signature, and hierarchy depth.
1103                 // This can only happen if at least one is vararg or generic.
1104                 if (currentHierarchyDepth == deepestHierarchy)
1105                 {
1106                     throw new AmbiguousMatchException("Arg_AmbiguousMatchException");
1107                 }
1108 
1109                 // Check to see if this method is on the most derived class.
1110                 if (currentHierarchyDepth > deepestHierarchy)
1111                 {
1112                     deepestHierarchy = currentHierarchyDepth;
1113                     methWithDeepestHierarchy = match[i];
1114                 }
1115             }
1116 
1117             return methWithDeepestHierarchy;
1118         }
1119 
1120 #if false
1121         // CanConvertPrimitive
1122         // This will determine if the source can be converted to the target type
1123         [System.Security.SecurityCritical]  // auto-generated
1124         [ResourceExposure(ResourceScope.None)]
1125         [MethodImplAttribute(MethodImplOptions.InternalCall)]
CanConvertPrimitive(RuntimeType source,RuntimeType target)1126         private static extern bool CanConvertPrimitive(RuntimeType source,RuntimeType target);
1127 
1128         // CanConvertPrimitiveObjectToType
1129         // This method will determine if the primitive object can be converted
1130         //  to a type.
1131         [System.Security.SecurityCritical]  // auto-generated
1132         [ResourceExposure(ResourceScope.None)]
1133         [MethodImplAttribute(MethodImplOptions.InternalCall)]
CanConvertPrimitiveObjectToType(Object source,RuntimeType type)1134         static internal extern bool CanConvertPrimitiveObjectToType(Object source,RuntimeType type);
1135 #else
CanConvertPrimitiveObjectToType(Object source, Type type)1136         static internal bool CanConvertPrimitiveObjectToType(Object source, Type type)
1137         {
1138             return CanConvertPrimitive(source.GetType(), type);
1139         }
1140 
1141         //  Logic copied from https://github.com/dotnet/coreclr/blob/bc146608854d1db9cdbcc0b08029a87754e12b49/src/vm/invokeutil.h#L186
CanConvertPrimitive(Type source, Type type)1142         static internal bool CanConvertPrimitive(Type source, Type type)
1143         {
1144             CorElementType srcType = GetCorElementType(source);
1145             CorElementType destType = GetCorElementType(type);
1146 
1147             if (srcType == CorElementType.ELEMENT_TYPE_END || destType == CorElementType.ELEMENT_TYPE_END)
1148             {
1149                 if ((source.GetType() == typeof(IntPtr) && type == typeof(IntPtr)) ||
1150                     (source.GetType() == typeof(UIntPtr) && type == typeof(UIntPtr)))
1151                 {
1152                     return true;
1153                 }
1154                 return false;
1155             }
1156 
1157             return ((1 << (int)destType) & PrimitiveAttributes[(int)srcType]) != 0;
1158         }
1159 
1160         //  Copied from: https://github.com/dotnet/coreclr/blob/bc146608854d1db9cdbcc0b08029a87754e12b49/src/inc/cortypeinfo.h
1161         //// TYPEINFO(type (CorElementType),  namespace, class,          size,           gcType,         isArray,isPrim, isFloat,isModifier,isGenVariable)
1162 
1163         //TYPEINFO(ELEMENT_TYPE_END,          NULL, NULL,                NO_SIZE,        TYPE_GC_NONE,   false,  false,  false,  false,  false) // 0x00
1164         //TYPEINFO(ELEMENT_TYPE_VOID,         "System", "Void",          0,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x01
1165         //TYPEINFO(ELEMENT_TYPE_BOOLEAN,      "System", "Boolean",       1,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x02
1166         //TYPEINFO(ELEMENT_TYPE_CHAR,         "System", "Char",          2,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x03
1167         //TYPEINFO(ELEMENT_TYPE_I1,           "System", "SByte",         1,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x04
1168         //TYPEINFO(ELEMENT_TYPE_U1,           "System", "Byte",          1,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x05
1169         //TYPEINFO(ELEMENT_TYPE_I2,           "System", "Int16",         2,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x06
1170         //TYPEINFO(ELEMENT_TYPE_U2,           "System", "UInt16",        2,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x07
1171         //TYPEINFO(ELEMENT_TYPE_I4,           "System", "Int32",         4,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x08
1172         //TYPEINFO(ELEMENT_TYPE_U4,           "System", "UInt32",        4,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x09
1173         //TYPEINFO(ELEMENT_TYPE_I8,           "System", "Int64",         8,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x0a
1174         //TYPEINFO(ELEMENT_TYPE_U8,           "System", "UInt64",        8,              TYPE_GC_NONE,   false,  true,   false,  false,  false) // 0x0b
1175 
1176         enum CorElementType
1177         {
1178             ELEMENT_TYPE_END = 0,
1179             ELEMENT_TYPE_VOID = 1,
1180             ELEMENT_TYPE_BOOLEAN = 2,
1181             ELEMENT_TYPE_CHAR = 3,
1182             ELEMENT_TYPE_I1 = 4,
1183             ELEMENT_TYPE_U1 = 5,
1184             ELEMENT_TYPE_I2 = 6,
1185             ELEMENT_TYPE_U2 = 7,
1186             ELEMENT_TYPE_I4 = 8,
1187             ELEMENT_TYPE_U4 = 9,
1188             ELEMENT_TYPE_I8 = 10,
1189             ELEMENT_TYPE_U8 = 11,
1190         }
1191 
GetCorElementType(Type type)1192         static private CorElementType GetCorElementType(Type type)
1193         {
1194             if (type == typeof(void))
1195             {
1196                 return CorElementType.ELEMENT_TYPE_END;
1197             }
1198             else if (type == typeof(bool))
1199             {
1200                 return CorElementType.ELEMENT_TYPE_BOOLEAN;
1201             }
1202             else if (type == typeof(char))
1203             {
1204                 return CorElementType.ELEMENT_TYPE_CHAR;
1205             }
1206             else if (type == typeof(SByte))
1207             {
1208                 return CorElementType.ELEMENT_TYPE_I1;
1209             }
1210             else if (type == typeof(Byte))
1211             {
1212                 return CorElementType.ELEMENT_TYPE_U1;
1213             }
1214             else if (type == typeof(Int16))
1215             {
1216                 return CorElementType.ELEMENT_TYPE_I2;
1217             }
1218             else if (type == typeof(UInt16))
1219             {
1220                 return CorElementType.ELEMENT_TYPE_U2;
1221             }
1222             else if (type == typeof(Int32))
1223             {
1224                 return CorElementType.ELEMENT_TYPE_I4;
1225             }
1226             else if (type == typeof(UInt32))
1227             {
1228                 return CorElementType.ELEMENT_TYPE_U4;
1229             }
1230             else if (type == typeof(Int64))
1231             {
1232                 return CorElementType.ELEMENT_TYPE_I8;
1233             }
1234             else if (type == typeof(UInt64))
1235             {
1236                 return CorElementType.ELEMENT_TYPE_U8;
1237             }
1238             return CorElementType.ELEMENT_TYPE_END;
1239         }
1240 
1241         //  Copied from https://github.com/dotnet/coreclr/blob/bc146608854d1db9cdbcc0b08029a87754e12b49/src/vm/invokeutil.h#L37
1242         //  #define PT_Primitive    0x01000000
1243         const uint PT_Primitive = 0x01000000;
1244 
1245         //  Copied from https://github.com/dotnet/coreclr/blob/bc146608854d1db9cdbcc0b08029a87754e12b49/src/vm/invokeutil.cpp#L37
1246         //const DWORD InvokeUtil::PrimitiveAttributes[PRIMITIVE_TABLE_SIZE] = {
1247         //    0x00,                     // ELEMENT_TYPE_END
1248         //    0x00,                     // ELEMENT_TYPE_VOID
1249         //    PT_Primitive | 0x0004,    // ELEMENT_TYPE_BOOLEAN
1250         //    PT_Primitive | 0x3F88,    // ELEMENT_TYPE_CHAR (W = U2, CHAR, I4, U4, I8, U8, R4, R8) (U2 == Char)
1251         //    PT_Primitive | 0x3550,    // ELEMENT_TYPE_I1   (W = I1, I2, I4, I8, R4, R8)
1252         //    PT_Primitive | 0x3FE8,    // ELEMENT_TYPE_U1   (W = CHAR, U1, I2, U2, I4, U4, I8, U8, R4, R8)
1253         //    PT_Primitive | 0x3540,    // ELEMENT_TYPE_I2   (W = I2, I4, I8, R4, R8)
1254         //    PT_Primitive | 0x3F88,    // ELEMENT_TYPE_U2   (W = U2, CHAR, I4, U4, I8, U8, R4, R8)
1255         //    PT_Primitive | 0x3500,    // ELEMENT_TYPE_I4   (W = I4, I8, R4, R8)
1256         //    PT_Primitive | 0x3E00,    // ELEMENT_TYPE_U4   (W = U4, I8, R4, R8)
1257         //    PT_Primitive | 0x3400,    // ELEMENT_TYPE_I8   (W = I8, R4, R8)
1258         //    PT_Primitive | 0x3800,    // ELEMENT_TYPE_U8   (W = U8, R4, R8)
1259         //    PT_Primitive | 0x3000,    // ELEMENT_TYPE_R4   (W = R4, R8)
1260         //    PT_Primitive | 0x2000,    // ELEMENT_TYPE_R8   (W = R8)
1261         //};
1262         private static readonly uint[] PrimitiveAttributes = new uint [] {
1263             0x00,                     // ELEMENT_TYPE_END
1264             0x00,                     // ELEMENT_TYPE_VOID
1265             PT_Primitive | 0x0004,    // ELEMENT_TYPE_BOOLEAN
1266             PT_Primitive | 0x3F88,    // ELEMENT_TYPE_CHAR (W = U2, CHAR, I4, U4, I8, U8, R4, R8) (U2 == Char)
1267             PT_Primitive | 0x3550,    // ELEMENT_TYPE_I1   (W = I1, I2, I4, I8, R4, R8)
1268             PT_Primitive | 0x3FE8,    // ELEMENT_TYPE_U1   (W = CHAR, U1, I2, U2, I4, U4, I8, U8, R4, R8)
1269             PT_Primitive | 0x3540,    // ELEMENT_TYPE_I2   (W = I2, I4, I8, R4, R8)
1270             PT_Primitive | 0x3F88,    // ELEMENT_TYPE_U2   (W = U2, CHAR, I4, U4, I8, U8, R4, R8)
1271             PT_Primitive | 0x3500,    // ELEMENT_TYPE_I4   (W = I4, I8, R4, R8)
1272             PT_Primitive | 0x3E00,    // ELEMENT_TYPE_U4   (W = U4, I8, R4, R8)
1273             PT_Primitive | 0x3400,    // ELEMENT_TYPE_I8   (W = I8, R4, R8)
1274             PT_Primitive | 0x3800,    // ELEMENT_TYPE_U8   (W = U8, R4, R8)
1275             PT_Primitive | 0x3000,    // ELEMENT_TYPE_R4   (W = R4, R8)
1276             PT_Primitive | 0x2000,    // ELEMENT_TYPE_R8   (W = R8)
1277         };
1278 #endif
1279 
1280         // This method will sort the vars array into the mapping order stored
1281         //  in the paramOrder array.
ReorderParams(int[] paramOrder,Object[] vars)1282         private static void ReorderParams(int[] paramOrder,Object[] vars)
1283         {
1284             object[] varsCopy = new object[vars.Length];
1285             for (int i = 0; i < vars.Length; i ++)
1286                 varsCopy[i] = vars[i];
1287 
1288             for (int i = 0; i < vars.Length; i ++)
1289                 vars[i] = varsCopy[paramOrder[i]];
1290         }
1291 
1292         // This method will create the mapping between the Parameters and the underlying
1293         //  data based upon the names array.  The names array is stored in the same order
1294         //  as the values and maps to the parameters of the method.  We store the mapping
1295         //  from the parameters to the names in the paramOrder array.  All parameters that
1296         //  don't have matching names are then stored in the array in order.
CreateParamOrder(int[] paramOrder,ParameterInfo[] pars,String[] names)1297         private static bool CreateParamOrder(int[] paramOrder,ParameterInfo[] pars,String[] names)
1298         {
1299             bool[] used = new bool[pars.Length];
1300 
1301             // Mark which parameters have not been found in the names list
1302             for (int i=0;i<pars.Length;i++)
1303                 paramOrder[i] = -1;
1304             // Find the parameters with names.
1305             for (int i=0;i<names.Length;i++) {
1306                 int j;
1307                 for (j=0;j<pars.Length;j++) {
1308                     if (names[i].Equals(pars[j].Name)) {
1309                         paramOrder[j] = i;
1310                         used[i] = true;
1311                         break;
1312                     }
1313                 }
1314                 // This is an error condition.  The name was not found.  This
1315                 //  method must not match what we sent.
1316                 if (j == pars.Length)
1317                     return false;
1318             }
1319 
1320             // Now we fill in the holes with the parameters that are unused.
1321             int pos = 0;
1322             for (int i=0;i<pars.Length;i++) {
1323                 if (paramOrder[i] == -1) {
1324                     for (;pos<pars.Length;pos++) {
1325                         if (!used[pos]) {
1326                             paramOrder[i] = pos;
1327                             pos++;
1328                             break;
1329                         }
1330                     }
1331                 }
1332             }
1333             return true;
1334         }
1335 
1336         internal class BinderState {
1337           internal int[] m_argsMap;
1338           internal int m_originalSize;
1339           internal bool m_isParamArray;
1340 
BinderState(int[] argsMap, int originalSize, bool isParamArray)1341           internal BinderState(int[] argsMap, int originalSize, bool isParamArray) {
1342               m_argsMap = argsMap;
1343               m_originalSize = originalSize;
1344               m_isParamArray = isParamArray;
1345           }
1346 
1347         }
1348     }
1349 }
1350