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