The Labs \ Source Viewer \ SSCLI \ System \ DefaultBinder

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. ////////////////////////////////////////////////////////////////////////////////
  16. ////////////////////////////////////////////////////////////////////////////////
  17. //
  18. // This class represents the Default COM+ binder.
  19. //
  20. //
  21. namespace System
  22. {
  23.    
  24.     using System;
  25.     using System.Reflection;
  26.     using System.Runtime.CompilerServices;
  27.     using CultureInfo = System.Globalization.CultureInfo;
  28.     //Marked serializable even though it has no state.
  29.     [Serializable()]
  30.     internal class DefaultBinder : Binder
  31.     {
  32.         // This method is passed a set of methods and must choose the best
  33.         // fit. The methods all have the same number of arguments and the object
  34.         // array args. On exit, this method will choice the best fit method
  35.         // and coerce the args to match that method. By match, we mean all primitive
  36.         // arguments are exact matchs and all object arguments are exact or subclasses
  37.         // of the target. If the target OR is an interface, the object must implement
  38.         // that interface. There are a couple of exceptions
  39.         // thrown when a method cannot be returned. If no method matchs the args and
  40.         // ArgumentException is thrown. If multiple methods match the args then
  41.         // an AmbiguousMatchException is thrown.
  42.         //
  43.         // The most specific match will be selected.
  44.         //
  45.         public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] canidates, ref object[] args, ParameterModifier[] modifiers, CultureInfo cultureInfo, string[] names, out object state)
  46.         {
  47.             int i;
  48.             int j;
  49.            
  50.             state = null;
  51.            
  52.             if (canidates == null || canidates.Length == 0)
  53.                 throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "canidates");
  54.            
  55.             #region Map named parameters to canidate parameter postions
  56.             // We are creating an paramOrder array to act as a mapping
  57.             // between the order of the args and the actual order of the
  58.             // parameters in the method. This order may differ because
  59.             // named parameters (names) may change the order. If names
  60.             // is not provided, then we assume the default mapping (0,1,...)
  61.             int[][] paramOrder = new int[canidates.Length][];
  62.            
  63.             for (i = 0; i < canidates.Length; i++) {
  64.                 ParameterInfo[] par = canidates[i].GetParametersNoCopy();
  65.                
  66.                 // args.Length + 1 takes into account the possibility of a last paramArray that can be omitted
  67.                 paramOrder[i] = new int[(par.Length > args.Length) ? par.Length : args.Length];
  68.                
  69.                 if (names == null) {
  70.                     // Default mapping
  71.                     for (j = 0; j < args.Length; j++)
  72.                         paramOrder[i][j] = j;
  73.                 }
  74.                 else {
  75.                     if (!CreateParamOrder(paramOrder[i], par, names))
  76.                         canidates[i] = null;
  77.                 }
  78.             }
  79.             #endregion
  80.            
  81.             Type[] paramArrayTypes = new Type[canidates.Length];
  82.            
  83.             Type[] argTypes = new Type[args.Length];
  84.            
  85.             #region Cache the type of the provided arguments
  86.             // object that contain a null are treated as if they were typeless (but match either object
  87.             // references or value classes). We mark this condition by placing a null in the argTypes array.
  88.             for (i = 0; i < args.Length; i++) {
  89.                 if (args[i] != null) {
  90.                     argTypes[i] = args[i].GetType();
  91.                 }
  92.             }
  93.             #endregion
  94.            
  95.            
  96.             // Find the method that matches...
  97.             int CurIdx = 0;
  98.             bool defaultValueBinding = ((bindingAttr & BindingFlags.OptionalParamBinding) != 0);
  99.            
  100.             Type paramArrayType = null;
  101.            
  102.             #region Filter methods by parameter count and type
  103.             for (i = 0; i < canidates.Length; i++) {
  104.                 paramArrayType = null;
  105.                
  106.                 // If we have named parameters then we may have a hole in the canidates array.
  107.                 if (canidates[i] == null)
  108.                     continue;
  109.                
  110.                 // Validate the parameters.
  111.                 ParameterInfo[] par = canidates[i].GetParametersNoCopy();
  112.                
  113.                 #region Match method by parameter count
  114.                 if (par.Length == 0) {
  115.                     #region No formal parameters
  116.                     if (args.Length != 0) {
  117.                         if ((canidates[i].CallingConvention & CallingConventions.VarArgs) == 0)
  118.                             continue;
  119.                     }
  120.                    
  121.                     // This is a valid routine so we move it up the canidates list.
  122.                     paramOrder[CurIdx] = paramOrder[i];
  123.                     canidates[CurIdx++] = canidates[i];
  124.                    
  125.                     continue;
  126.                     #endregion
  127.                 }
  128.                 else if (par.Length > args.Length) {
  129.                     #region Shortage of provided parameters
  130.                     // If the number of parameters is greater than the number of args then
  131.                     // we are in the situation were we may be using default values.
  132.                     for (j = args.Length; j < par.Length - 1; j++) {
  133.                         if (par[j].DefaultValue == System.DBNull.Value)
  134.                             break;
  135.                     }
  136.                    
  137.                     if (j != par.Length - 1)
  138.                         continue;
  139.                    
  140.                     if (par[j].DefaultValue == System.DBNull.Value) {
  141.                         if (!par[j].ParameterType.IsArray)
  142.                             continue;
  143.                        
  144.                         if (!par[j].IsDefined(typeof(ParamArrayAttribute), true))
  145.                             continue;
  146.                        
  147.                         paramArrayType = par[j].ParameterType.GetElementType();
  148.                     }
  149.                     #endregion
  150.                 }
  151.                 else if (par.Length < args.Length) {
  152.                     #region Excess provided parameters
  153.                     // test for the ParamArray case
  154.                     int lastArgPos = par.Length - 1;
  155.                    
  156.                     if (!par[lastArgPos].ParameterType.IsArray)
  157.                         continue;
  158.                    
  159.                     if (!par[lastArgPos].IsDefined(typeof(ParamArrayAttribute), true))
  160.                         continue;
  161.                    
  162.                     if (paramOrder[i][lastArgPos] != lastArgPos)
  163.                         continue;
  164.                    
  165.                     paramArrayType = par[lastArgPos].ParameterType.GetElementType();
  166.                     #endregion
  167.                 }
  168.                 else {
  169.                     #region Test for paramArray, save paramArray type
  170.                     int lastArgPos = par.Length - 1;
  171.                    
  172.                     if (par[lastArgPos].ParameterType.IsArray && par[lastArgPos].IsDefined(typeof(ParamArrayAttribute), true) && paramOrder[i][lastArgPos] == lastArgPos) {
  173.                         if (!par[lastArgPos].ParameterType.IsAssignableFrom(argTypes[lastArgPos]))
  174.                             paramArrayType = par[lastArgPos].ParameterType.GetElementType();
  175.                     }
  176.                     #endregion
  177.                 }
  178.                 #endregion
  179.                
  180.                 Type pCls = null;
  181.                 int argsToCheck = (paramArrayType != null) ? par.Length - 1 : args.Length;
  182.                
  183.                 #region Match method by parameter type
  184.                 for (j = 0; j < argsToCheck; j++) {
  185.                     #region Classic argument coersion checks
  186.                     // get the formal type
  187.                     pCls = par[j].ParameterType;
  188.                    
  189.                     if (pCls.IsByRef)
  190.                         pCls = pCls.GetElementType();
  191.                    
  192.                     // the type is the same
  193.                     if (pCls == argTypes[paramOrder[i][j]])
  194.                         continue;
  195.                    
  196.                     // a default value is available
  197.                     if (defaultValueBinding && args[paramOrder[i][j]] == Type.Missing)
  198.                         continue;
  199.                    
  200.                     // the argument was null, so it matches with everything
  201.                     if (args[paramOrder[i][j]] == null)
  202.                         continue;
  203.                    
  204.                     // the type is Object, so it will match everything
  205.                     if (pCls == typeof(object))
  206.                         continue;
  207.                    
  208.                     // now do a "classic" type check
  209.                     if (pCls.IsPrimitive) {
  210.                         if (argTypes[paramOrder[i][j]] == null || !CanConvertPrimitiveObjectToType(args[paramOrder[i][j]], (RuntimeType)pCls)) {
  211.                             if (CanChangeType(args[paramOrder[i][j]], pCls, cultureInfo))
  212.                                 continue;
  213.                             break;
  214.                         }
  215.                     }
  216.                     else {
  217.                         if (argTypes[paramOrder[i][j]] == null)
  218.                             continue;
  219.                        
  220.                         if (!pCls.IsAssignableFrom(argTypes[paramOrder[i][j]])) {
  221.                             if (argTypes[paramOrder[i][j]].IsCOMObject) {
  222.                                 if (pCls.IsInstanceOfType(args[paramOrder[i][j]]))
  223.                                     continue;
  224.                             }
  225.                             if (CanChangeType(args[paramOrder[i][j]], pCls, cultureInfo))
  226.                                 continue;
  227.                             break;
  228.                         }
  229.                     }
  230.                     #endregion
  231.                 }
  232.                
  233.                 if (paramArrayType != null && j == par.Length - 1) {
  234.                     #region Check that excess arguments can be placed in the param array
  235.                     for (; j < args.Length; j++) {
  236.                         if (paramArrayType.IsPrimitive) {
  237.                             if (argTypes[j] == null || !CanConvertPrimitiveObjectToType(args[j], (RuntimeType)paramArrayType))
  238.                                 break;
  239.                         }
  240.                         else {
  241.                             if (argTypes[j] == null)
  242.                                 continue;
  243.                            
  244.                             if (!paramArrayType.IsAssignableFrom(argTypes[j])) {
  245.                                 if (argTypes[j].IsCOMObject) {
  246.                                     if (paramArrayType.IsInstanceOfType(args[j]))
  247.                                         continue;
  248.                                 }
  249.                                
  250.                                 break;
  251.                             }
  252.                         }
  253.                     }
  254.                     #endregion
  255.                 }
  256.                 #endregion
  257.                
  258.                 if (j == args.Length) {
  259.                     #region This is a valid routine so we move it up the canidates list
  260.                     paramOrder[CurIdx] = paramOrder[i];
  261.                     paramArrayTypes[CurIdx] = paramArrayType;
  262.                     canidates[CurIdx++] = canidates[i];
  263.                     #endregion
  264.                 }
  265.             }
  266.             #endregion
  267.            
  268.             // If we didn't find a method
  269.             if (CurIdx == 0)
  270.                 throw new MissingMethodException(Environment.GetResourceString("MissingMember"));
  271.            
  272.             if (CurIdx == 1) {
  273.                 #region Found only one method
  274.                 if (names != null) {
  275.                     state = new BinderState((int[])paramOrder[0].Clone(), args.Length, paramArrayTypes[0] != null);
  276.                     ReorderParams(paramOrder[0], args);
  277.                 }
  278.                
  279.                 // If the parameters and the args are not the same length or there is a paramArray
  280.                 // then we need to create a argument array.
  281.                 ParameterInfo[] parms = canidates[0].GetParametersNoCopy();
  282.                
  283.                 if (parms.Length == args.Length) {
  284.                     if (paramArrayTypes[0] != null) {
  285.                         object[] objs = new object[parms.Length];
  286.                         int lastPos = parms.Length - 1;
  287.                         Array.Copy(args, 0, objs, 0, lastPos);
  288.                         objs[lastPos] = Array.CreateInstance(paramArrayTypes[0], 1);
  289.                         ((Array)objs[lastPos]).SetValue(args[lastPos], 0);
  290.                         args = objs;
  291.                     }
  292.                 }
  293.                 else if (parms.Length > args.Length) {
  294.                     object[] objs = new object[parms.Length];
  295.                    
  296.                     for (i = 0; i < args.Length; i++)
  297.                         objs[i] = args[i];
  298.                    
  299.                     for (; i < parms.Length - 1; i++)
  300.                         objs[i] = parms[i].DefaultValue;
  301.                    
  302.                     if (paramArrayTypes[0] != null)
  303.                         objs[i] = Array.CreateInstance(paramArrayTypes[0], 0);
  304.                     else
  305.                         // create an empty array for the
  306.                         objs[i] = parms[i].DefaultValue;
  307.                    
  308.                     args = objs;
  309.                 }
  310.                 else {
  311.                     if ((canidates[0].CallingConvention & CallingConventions.VarArgs) == 0) {
  312.                         object[] objs = new object[parms.Length];
  313.                         int paramArrayPos = parms.Length - 1;
  314.                         Array.Copy(args, 0, objs, 0, paramArrayPos);
  315.                         objs[paramArrayPos] = Array.CreateInstance(paramArrayTypes[0], args.Length - paramArrayPos);
  316.                         Array.Copy(args, paramArrayPos, (System.Array)objs[paramArrayPos], 0, args.Length - paramArrayPos);
  317.                         args = objs;
  318.                     }
  319.                 }
  320.                 #endregion
  321.                
  322.                 return canidates[0];
  323.             }
  324.            
  325.             int currentMin = 0;
  326.             bool ambig = false;
  327.             for (i = 1; i < CurIdx; i++) {
  328.                 #region Walk all of the methods looking the most specific method to invoke
  329.                 int newMin = FindMostSpecificMethod(canidates[currentMin], paramOrder[currentMin], paramArrayTypes[currentMin], canidates[i], paramOrder[i], paramArrayTypes[i], argTypes, args);
  330.                
  331.                 if (newMin == 0) {
  332.                     ambig = true;
  333.                 }
  334.                 else if (newMin == 2) {
  335.                     currentMin = i;
  336.                     ambig = false;
  337.                 }
  338.                 #endregion
  339.             }
  340.            
  341.             if (ambig)
  342.                 throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.Ambiguous"));
  343.            
  344.             // Reorder (if needed)
  345.             if (names != null) {
  346.                 state = new BinderState((int[])paramOrder[currentMin].Clone(), args.Length, paramArrayTypes[currentMin] != null);
  347.                 ReorderParams(paramOrder[currentMin], args);
  348.             }
  349.            
  350.             // If the parameters and the args are not the same length or there is a paramArray
  351.             // then we need to create a argument array.
  352.             ParameterInfo[] parameters = canidates[currentMin].GetParametersNoCopy();
  353.             if (parameters.Length == args.Length) {
  354.                 if (paramArrayTypes[currentMin] != null) {
  355.                     object[] objs = new object[parameters.Length];
  356.                     int lastPos = parameters.Length - 1;
  357.                     Array.Copy(args, 0, objs, 0, lastPos);
  358.                     objs[lastPos] = Array.CreateInstance(paramArrayTypes[currentMin], 1);
  359.                     ((Array)objs[lastPos]).SetValue(args[lastPos], 0);
  360.                     args = objs;
  361.                 }
  362.             }
  363.             else if (parameters.Length > args.Length) {
  364.                 object[] objs = new object[parameters.Length];
  365.                
  366.                 for (i = 0; i < args.Length; i++)
  367.                     objs[i] = args[i];
  368.                
  369.                 for (; i < parameters.Length - 1; i++)
  370.                     objs[i] = parameters[i].DefaultValue;
  371.                
  372.                 if (paramArrayTypes[currentMin] != null) {
  373.                     objs[i] = Array.CreateInstance(paramArrayTypes[currentMin], 0);
  374.                 }
  375.                 else {
  376.                     objs[i] = parameters[i].DefaultValue;
  377.                 }
  378.                
  379.                 args = objs;
  380.             }
  381.             else {
  382.                 if ((canidates[currentMin].CallingConvention & CallingConventions.VarArgs) == 0) {
  383.                     object[] objs = new object[parameters.Length];
  384.                     int paramArrayPos = parameters.Length - 1;
  385.                     Array.Copy(args, 0, objs, 0, paramArrayPos);
  386.                     objs[i] = Array.CreateInstance(paramArrayTypes[currentMin], args.Length - paramArrayPos);
  387.                     Array.Copy(args, paramArrayPos, (System.Array)objs[i], 0, args.Length - paramArrayPos);
  388.                     args = objs;
  389.                 }
  390.             }
  391.            
  392.             return canidates[currentMin];
  393.         }
  394.        
  395.        
  396.         // Given a set of fields that match the base criteria, select a field.
  397.         // if value is null then we have no way to select a field
  398.         public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo cultureInfo)
  399.         {
  400.             int i;
  401.             // Find the method that match...
  402.             int CurIdx = 0;
  403.            
  404.             Type valueType = null;
  405.            
  406.             // If we are a FieldSet, then use the value's type to disambiguate
  407.             if ((bindingAttr & BindingFlags.SetField) != 0) {
  408.                 valueType = value.GetType();
  409.                
  410.                 for (i = 0; i < match.Length; i++) {
  411.                     Type pCls = match[i].FieldType;
  412.                     if (pCls == valueType) {
  413.                         match[CurIdx++] = match[i];
  414.                         continue;
  415.                     }
  416.                     if (value == Empty.Value) {
  417.                         // the object passed in was null which would match any non primitive non value type
  418.                         if (pCls.IsClass) {
  419.                             match[CurIdx++] = match[i];
  420.                             continue;
  421.                         }
  422.                     }
  423.                     if (pCls == typeof(object)) {
  424.                         match[CurIdx++] = match[i];
  425.                         continue;
  426.                     }
  427.                     if (pCls.IsPrimitive) {
  428.                         if (CanConvertPrimitiveObjectToType(value, (RuntimeType)pCls)) {
  429.                             match[CurIdx++] = match[i];
  430.                             continue;
  431.                         }
  432.                     }
  433.                     else {
  434.                         if (pCls.IsAssignableFrom(valueType)) {
  435.                             match[CurIdx++] = match[i];
  436.                             continue;
  437.                         }
  438.                     }
  439.                 }
  440.                 if (CurIdx == 0)
  441.                     throw new MissingFieldException(Environment.GetResourceString("MissingField"));
  442.                 if (CurIdx == 1)
  443.                     return match[0];
  444.             }
  445.            
  446.             // Walk all of the methods looking the most specific method to invoke
  447.             int currentMin = 0;
  448.             bool ambig = false;
  449.             for (i = 1; i < CurIdx; i++) {
  450.                 int newMin = FindMostSpecificField(match[currentMin], match[i]);
  451.                 if (newMin == 0)
  452.                     ambig = true;
  453.                 else {
  454.                     if (newMin == 2) {
  455.                         currentMin = i;
  456.                         ambig = false;
  457.                     }
  458.                 }
  459.             }
  460.             if (ambig)
  461.                 throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.Ambiguous"));
  462.             return match[currentMin];
  463.         }
  464.        
  465.         // Given a set of methods that match the base criteria, select a method based
  466.         // upon an array of types. This method should return null if no method matchs
  467.         // the criteria.
  468.         public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
  469.         {
  470.             int i;
  471.             int j;
  472.            
  473.             Type[] realTypes = new Type[types.Length];
  474.             for (i = 0; i < types.Length; i++) {
  475.                 realTypes[i] = types[i].UnderlyingSystemType;
  476.                 if (!(realTypes[i] is RuntimeType))
  477.                     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "types");
  478.             }
  479.             types = realTypes;
  480.            
  481.             // We don't automatically jump out on exact match.
  482.             if (match == null || match.Length == 0)
  483.                 throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "match");
  484.            
  485.             // Find all the methods that can be described by the types parameter.
  486.             // Remove all of them that cannot.
  487.             int CurIdx = 0;
  488.             for (i = 0; i < match.Length; i++) {
  489.                 //Console.WriteLine(match[i]);
  490.                 ParameterInfo[] par = match[i].GetParametersNoCopy();
  491.                 if (par.Length != types.Length)
  492.                     continue;
  493.                 for (j = 0; j < types.Length; j++) {
  494.                     Type pCls = par[j].ParameterType;
  495.                     //Console.WriteLine(pCls);
  496.                     if (pCls == types[j])
  497.                         continue;
  498.                     if (pCls == typeof(object))
  499.                         continue;
  500.                     if (pCls.IsPrimitive) {
  501.                         if (!(types[j].UnderlyingSystemType is RuntimeType) || !CanConvertPrimitive((RuntimeType)types[j].UnderlyingSystemType, (RuntimeType)pCls.UnderlyingSystemType))
  502.                             break;
  503.                     }
  504.                     else {
  505.                         if (!pCls.IsAssignableFrom(types[j]))
  506.                             break;
  507.                     }
  508.                 }
  509.                 if (j == types.Length)
  510.                     match[CurIdx++] = match[i];
  511.             }
  512.             if (CurIdx == 0)
  513.                 return null;
  514.             if (CurIdx == 1)
  515.                 return match[0];
  516.            
  517.             // Walk all of the methods looking the most specific method to invoke
  518.             int currentMin = 0;
  519.             bool ambig = false;
  520.             int[] paramOrder = new int[types.Length];
  521.             for (i = 0; i < types.Length; i++)
  522.                 paramOrder[i] = i;
  523.             for (i = 1; i < CurIdx; i++) {
  524.                 int newMin = FindMostSpecificMethod(match[currentMin], paramOrder, null, match[i], paramOrder, null, types, null);
  525.                 if (newMin == 0)
  526.                     ambig = true;
  527.                 else {
  528.                     if (newMin == 2) {
  529.                         currentMin = i;
  530.                         ambig = false;
  531.                         currentMin = i;
  532.                     }
  533.                 }
  534.             }
  535.             if (ambig)
  536.                 throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.Ambiguous"));
  537.             return match[currentMin];
  538.         }
  539.        
  540.         // Given a set of propreties that match the base criteria, select one.
  541.         public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
  542.         {
  543.             int i;
  544.             int j = 0;
  545.             if (match == null || match.Length == 0)
  546.                 throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "match");
  547.            
  548.             // Find all the properties that can be described by type indexes parameter
  549.             int CurIdx = 0;
  550.             int indexesLength = (indexes != null) ? indexes.Length : 0;
  551.             for (i = 0; i < match.Length; i++) {
  552.                
  553.                 if (indexes != null) {
  554.                     ParameterInfo[] par = match[i].GetIndexParameters();
  555.                     if (par.Length != indexesLength)
  556.                         continue;
  557.                    
  558.                     for (j = 0; j < indexesLength; j++) {
  559.                         Type pCls = par[j].ParameterType;
  560.                        
  561.                         // If the classes exactly match continue
  562.                         if (pCls == indexes[j])
  563.                             continue;
  564.                         if (pCls == typeof(object))
  565.                             continue;
  566.                        
  567.                         if (pCls.IsPrimitive) {
  568.                             if (!(indexes[j].UnderlyingSystemType is RuntimeType) || !CanConvertPrimitive((RuntimeType)indexes[j].UnderlyingSystemType, (RuntimeType)pCls.UnderlyingSystemType))
  569.                                 break;
  570.                         }
  571.                         else {
  572.                             if (!pCls.IsAssignableFrom(indexes[j]))
  573.                                 break;
  574.                         }
  575.                     }
  576.                 }
  577.                
  578.                 if (j == indexesLength) {
  579.                     if (returnType != null) {
  580.                         if (match[i].PropertyType.IsPrimitive) {
  581.                             if (!(returnType.UnderlyingSystemType is RuntimeType) || !CanConvertPrimitive((RuntimeType)returnType.UnderlyingSystemType, (RuntimeType)match[i].PropertyType.UnderlyingSystemType))
  582.                                 continue;
  583.                         }
  584.                         else {
  585.                             if (!match[i].PropertyType.IsAssignableFrom(returnType))
  586.                                 continue;
  587.                         }
  588.                     }
  589.                     match[CurIdx++] = match[i];
  590.                 }
  591.             }
  592.             if (CurIdx == 0)
  593.                 return null;
  594.             if (CurIdx == 1)
  595.                 return match[0];
  596.            
  597.             // Walk all of the properties looking the most specific method to invoke
  598.             int currentMin = 0;
  599.             bool ambig = false;
  600.             int[] paramOrder = new int[indexesLength];
  601.             for (i = 0; i < indexesLength; i++)
  602.                 paramOrder[i] = i;
  603.             for (i = 1; i < CurIdx; i++) {
  604.                 int newMin = FindMostSpecificType(match[currentMin].PropertyType, match[i].PropertyType, returnType);
  605.                 if (newMin == 0 && indexes != null)
  606.                     newMin = FindMostSpecific(match[currentMin].GetIndexParameters(), paramOrder, null, match[i].GetIndexParameters(), paramOrder, null, indexes, null);
  607.                 if (newMin == 0) {
  608.                     newMin = FindMostSpecificProperty(match[currentMin], match[i]);
  609.                     if (newMin == 0)
  610.                         ambig = true;
  611.                 }
  612.                 if (newMin == 2) {
  613.                     ambig = false;
  614.                     currentMin = i;
  615.                 }
  616.             }
  617.            
  618.             if (ambig)
  619.                 throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.Ambiguous"));
  620.             return match[currentMin];
  621.         }
  622.        
  623.         // ChangeType
  624.         // The default binder doesn't support any change type functionality.
  625.         // This is because the default is built into the low level invoke code.
  626.         public override object ChangeType(object value, Type type, CultureInfo cultureInfo)
  627.         {
  628.             throw new NotSupportedException(Environment.GetResourceString("NotSupported_ChangeType"));
  629.         }
  630.        
  631.         public override void ReorderArgumentArray(ref object[] args, object state)
  632.         {
  633.             BinderState binderState = (BinderState)state;
  634.             ReorderParams(binderState.m_argsMap, args);
  635.             if (binderState.m_isParamArray) {
  636.                 int paramArrayPos = args.Length - 1;
  637.                 if (args.Length == binderState.m_originalSize)
  638.                     args[paramArrayPos] = ((object[])args[paramArrayPos])[0];
  639.                 else {
  640.                     // must be args.Length < state.originalSize
  641.                     object[] newArgs = new object[args.Length];
  642.                     Array.Copy(args, 0, newArgs, 0, paramArrayPos);
  643.                     for (int i = paramArrayPosint j = 0; i < newArgs.Length; i++,j++) {
  644.                         newArgs[i] = ((object[])args[paramArrayPos])[j];
  645.                     }
  646.                     args = newArgs;
  647.                 }
  648.             }
  649.             else {
  650.                 if (args.Length > binderState.m_originalSize) {
  651.                     object[] newArgs = new object[binderState.m_originalSize];
  652.                     Array.Copy(args, 0, newArgs, 0, binderState.m_originalSize);
  653.                     args = newArgs;
  654.                 }
  655.             }
  656.         }
  657.        
  658.         // Return any exact bindings that may exist. (This method is not defined on the
  659.         // Binder and is used by RuntimeType.)
  660.         public static MethodBase ExactBinding(MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
  661.         {
  662.             if (match == null)
  663.                 throw new ArgumentNullException("match");
  664.             MethodBase[] aExactMatches = new MethodBase[match.Length];
  665.             int cExactMatches = 0;
  666.            
  667.             for (int i = 0; i < match.Length; i++) {
  668.                 ParameterInfo[] par = match[i].GetParametersNoCopy();
  669.                 if (par.Length == 0) {
  670.                     continue;
  671.                 }
  672.                 int j;
  673.                 for (j = 0; j < types.Length; j++) {
  674.                     Type pCls = par[j].ParameterType;
  675.                    
  676.                     // If the classes exactly match continue
  677.                     if (!pCls.Equals(types[j]))
  678.                         break;
  679.                 }
  680.                 if (j < types.Length)
  681.                     continue;
  682.                
  683.                 // Add the exact match to the array of exact matches.
  684.                 aExactMatches[cExactMatches] = match[i];
  685.                 cExactMatches++;
  686.             }
  687.            
  688.             if (cExactMatches == 0)
  689.                 return null;
  690.            
  691.             if (cExactMatches == 1)
  692.                 return aExactMatches[0];
  693.            
  694.             return FindMostDerivedNewSlotMeth(aExactMatches, cExactMatches);
  695.         }
  696.        
  697.         // Return any exact bindings that may exist. (This method is not defined on the
  698.         // Binder and is used by RuntimeType.)
  699.         public static PropertyInfo ExactPropertyBinding(PropertyInfo[] match, Type returnType, Type[] types, ParameterModifier[] modifiers)
  700.         {
  701.             if (match == null)
  702.                 throw new ArgumentNullException("match");
  703.            
  704.             PropertyInfo bestMatch = null;
  705.             int typesLength = (types != null) ? types.Length : 0;
  706.             for (int i = 0; i < match.Length; i++) {
  707.                 ParameterInfo[] par = match[i].GetIndexParameters();
  708.                 int j;
  709.                 for (j = 0; j < typesLength; j++) {
  710.                     Type pCls = par[j].ParameterType;
  711.                    
  712.                     // If the classes exactly match continue
  713.                     if (pCls != types[j])
  714.                         break;
  715.                 }
  716.                 if (j < typesLength)
  717.                     continue;
  718.                 if (returnType != null && returnType != match[i].PropertyType)
  719.                     continue;
  720.                
  721.                 if (bestMatch != null)
  722.                     throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.Ambiguous"));
  723.                
  724.                 bestMatch = match[i];
  725.             }
  726.             return bestMatch;
  727.         }
  728.        
  729.         private static int FindMostSpecific(ParameterInfo[] p1, int[] paramOrder1, Type paramArrayType1, ParameterInfo[] p2, int[] paramOrder2, Type paramArrayType2, Type[] types, object[] args)
  730.         {
  731.             // A method using params is always less specific than one not using params
  732.             if (paramArrayType1 != null && paramArrayType2 == null)
  733.                 return 2;
  734.             if (paramArrayType2 != null && paramArrayType1 == null)
  735.                 return 1;
  736.            
  737.             bool p1Less = false;
  738.             bool p2Less = false;
  739.            
  740.             for (int i = 0; i < types.Length; i++) {
  741.                 if (args != null && args[i] == Type.Missing)
  742.                     continue;
  743.                
  744.                 Type c1 = p1[paramOrder1[i]].ParameterType;
  745.                 Type c2 = p2[paramOrder2[i]].ParameterType;
  746.                
  747.                 if (i == p1.Length - 1 && paramOrder1[i] == p1.Length - 1 && paramArrayType1 != null)
  748.                     c1 = paramArrayType1;
  749.                 if (i == p2.Length - 1 && paramOrder2[i] == p2.Length - 1 && paramArrayType2 != null)
  750.                     c2 = paramArrayType2;
  751.                
  752.                 if (c1 == c2)
  753.                     continue;
  754.                
  755.                 switch (FindMostSpecificType(c1, c2, types[i])) {
  756.                     case 0:
  757.                         return 0;
  758.                     case 1:
  759.                         p1Less = true;
  760.                         break;
  761.                     case 2:
  762.                         p2Less = true;
  763.                         break;
  764.                 }
  765.             }
  766.            
  767.             // Two way p1Less and p2Less can be equal. All the arguments are the
  768.             // same they both equal false, otherwise there were things that both
  769.             // were the most specific type on....
  770.             if (p1Less == p2Less) {
  771.                 // it's possible that the 2 methods have same sig and default param in which case we match the one
  772.                 // with the same number of args but only if they were exactly the same (that is p1Less and p2Lees are both false)
  773.                 if (!p1Less && p1.Length != p2.Length && args != null) {
  774.                     if (p1.Length == args.Length) {
  775.                         return 1;
  776.                     }
  777.                     else if (p2.Length == args.Length) {
  778.                         return 2;
  779.                     }
  780.                 }
  781.                
  782.                 return 0;
  783.             }
  784.             else {
  785.                 return (p1Less == true) ? 1 : 2;
  786.             }
  787.         }
  788.        
  789.         private static int FindMostSpecificType(Type c1, Type c2, Type t)
  790.         {
  791.             // If the two types are exact move on...
  792.             if (c1 == c2)
  793.                 return 0;
  794.            
  795.             if (c1 == t)
  796.                 return 1;
  797.            
  798.             if (c2 == t)
  799.                 return 2;
  800.            
  801.             bool c1FromC2;
  802.             bool c2FromC1;
  803.            
  804.             if (c1.IsByRef || c2.IsByRef) {
  805.                 if (c1.IsByRef && c2.IsByRef) {
  806.                     c1 = c1.GetElementType();
  807.                     c2 = c2.GetElementType();
  808.                 }
  809.                 else if (c1.IsByRef) {
  810.                     if (c1.GetElementType() == c2)
  811.                         return 2;
  812.                    
  813.                     c1 = c1.GetElementType();
  814.                 }
  815.                 else {
  816.                     if (c2.GetElementType() == c1)
  817.                         return 1;
  818.                    
  819.                     c2 = c2.GetElementType();
  820.                 }
  821.             }
  822.            
  823.            
  824.             if (c1.IsPrimitive && c2.IsPrimitive) {
  825.                 c1FromC2 = CanConvertPrimitive((RuntimeType)c2, (RuntimeType)c1);
  826.                 c2FromC1 = CanConvertPrimitive((RuntimeType)c1, (RuntimeType)c2);
  827.             }
  828.             else {
  829.                 c1FromC2 = c1.IsAssignableFrom(c2);
  830.                 c2FromC1 = c2.IsAssignableFrom(c1);
  831.             }
  832.            
  833.             if (c1FromC2 == c2FromC1)
  834.                 return 0;
  835.            
  836.             if (c1FromC2) {
  837.                 return 2;
  838.             }
  839.             else {
  840.                 return 1;
  841.             }
  842.         }
  843.        
  844.         private static int FindMostSpecificMethod(MethodBase m1, int[] paramOrder1, Type paramArrayType1, MethodBase m2, int[] paramOrder2, Type paramArrayType2, Type[] types, object[] args)
  845.         {
  846.             // Find the most specific method based on the parameters.
  847.             int res = FindMostSpecific(m1.GetParametersNoCopy(), paramOrder1, paramArrayType1, m2.GetParametersNoCopy(), paramOrder2, paramArrayType2, types, args);
  848.            
  849.             // If the match was not ambigous then return the result.
  850.             if (res != 0)
  851.                 return res;
  852.            
  853.             // Check to see if the methods have the exact same name and signature.
  854.             if (CompareMethodSigAndName(m1, m2)) {
  855.                 // Determine the depth of the declaring types for both methods.
  856.                 int hierarchyDepth1 = GetHierarchyDepth(m1.DeclaringType);
  857.                 int hierarchyDepth2 = GetHierarchyDepth(m2.DeclaringType);
  858.                
  859.                 // The most derived method is the most specific one.
  860.                 if (hierarchyDepth1 == hierarchyDepth2) {
  861.                     return 0;
  862.                 }
  863.                 else if (hierarchyDepth1 < hierarchyDepth2) {
  864.                     return 2;
  865.                 }
  866.                 else {
  867.                     return 1;
  868.                 }
  869.             }
  870.            
  871.             // The match is ambigous.
  872.             return 0;
  873.         }
  874.        
  875.         private static int FindMostSpecificField(FieldInfo cur1, FieldInfo cur2)
  876.         {
  877.             // Check to see if the fields have the same name.
  878.             if (cur1.Name == cur2.Name) {
  879.                 int hierarchyDepth1 = GetHierarchyDepth(cur1.DeclaringType);
  880.                 int hierarchyDepth2 = GetHierarchyDepth(cur2.DeclaringType);
  881.                
  882.                 if (hierarchyDepth1 == hierarchyDepth2) {
  883.                     BCLDebug.Assert(cur1.IsStatic != cur2.IsStatic, "hierarchyDepth1 == hierarchyDepth2");
  884.                     return 0;
  885.                 }
  886.                 else if (hierarchyDepth1 < hierarchyDepth2)
  887.                     return 2;
  888.                 else
  889.                     return 1;
  890.             }
  891.            
  892.             // The match is ambigous.
  893.             return 0;
  894.         }
  895.        
  896.         private static int FindMostSpecificProperty(PropertyInfo cur1, PropertyInfo cur2)
  897.         {
  898.             // Check to see if the fields have the same name.
  899.             if (cur1.Name == cur2.Name) {
  900.                 int hierarchyDepth1 = GetHierarchyDepth(cur1.DeclaringType);
  901.                 int hierarchyDepth2 = GetHierarchyDepth(cur2.DeclaringType);
  902.                
  903.                 if (hierarchyDepth1 == hierarchyDepth2) {
  904.                     return 0;
  905.                 }
  906.                 else if (hierarchyDepth1 < hierarchyDepth2)
  907.                     return 2;
  908.                 else
  909.                     return 1;
  910.             }
  911.            
  912.             // The match is ambigous.
  913.             return 0;
  914.         }
  915.        
  916.         static internal bool CompareMethodSigAndName(MethodBase m1, MethodBase m2)
  917.         {
  918.             ParameterInfo[] params1 = m1.GetParametersNoCopy();
  919.             ParameterInfo[] params2 = m2.GetParametersNoCopy();
  920.            
  921.             if (params1.Length != params2.Length)
  922.                 return false;
  923.            
  924.             int numParams = params1.Length;
  925.             for (int i = 0; i < numParams; i++) {
  926.                 if (params1[i].ParameterType != params2[i].ParameterType)
  927.                     return false;
  928.             }
  929.            
  930.             return true;
  931.         }
  932.        
  933.         static internal int GetHierarchyDepth(Type t)
  934.         {
  935.             int depth = 0;
  936.            
  937.             Type currentType = t;
  938.             do {
  939.                 depth++;
  940.                 currentType = currentType.BaseType;
  941.             }
  942.             while (currentType != null);
  943.            
  944.             return depth;
  945.         }
  946.        
  947.         static internal MethodBase FindMostDerivedNewSlotMeth(MethodBase[] match, int cMatches)
  948.         {
  949.             int deepestHierarchy = 0;
  950.             MethodBase methWithDeepestHierarchy = null;
  951.            
  952.             for (int i = 0; i < cMatches; i++) {
  953.                 // Calculate the depth of the hierarchy of the declaring type of the
  954.                 // current method.
  955.                 int currentHierarchyDepth = GetHierarchyDepth(match[i].DeclaringType);
  956.                
  957.                 // Two methods with the same hierarchy depth are not allowed. This would
  958.                 // mean that there are 2 methods with the same name and sig on a given type
  959.                 // which is not allowed, unless one of them is vararg...
  960.                 if (currentHierarchyDepth == deepestHierarchy) {
  961.                     BCLDebug.Assert(((match[i].CallingConvention & CallingConventions.VarArgs) | (methWithDeepestHierarchy.CallingConvention & CallingConventions.VarArgs)) != 0, "Calling conventions: " + match[i].CallingConvention + " - " + methWithDeepestHierarchy.CallingConvention);
  962.                     throw new AmbiguousMatchException(Environment.GetResourceString("RFLCT.Ambiguous"));
  963.                 }
  964.                
  965.                 // Check to see if this method is on the most derived class.
  966.                 if (currentHierarchyDepth > deepestHierarchy) {
  967.                     deepestHierarchy = currentHierarchyDepth;
  968.                     methWithDeepestHierarchy = match[i];
  969.                 }
  970.             }
  971.            
  972.             return methWithDeepestHierarchy;
  973.         }
  974.        
  975.         // CanConvertPrimitive
  976.         // This will determine if the source can be converted to the target type
  977.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  978.         private static extern bool CanConvertPrimitive(RuntimeType source, RuntimeType target);
  979.        
  980.         // CanConvertPrimitiveObjectToType
  981.         // This method will determine if the primitive object can be converted
  982.         // to a type.
  983.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  984.         static internal extern bool CanConvertPrimitiveObjectToType(object source, RuntimeType type);
  985.        
  986.         // This method will sort the vars array into the mapping order stored
  987.         // in the paramOrder array.
  988.         private static void ReorderParams(int[] paramOrder, object[] vars)
  989.         {
  990.             // This is an O(n) algorithm for sorting the array.
  991.             // For each position in the paramOrder array we swap the value
  992.             // stored there into it's position until we swap position i into i.
  993.             // This moves things exactly the number of items out of position.
  994.             for (int i = 0; i < vars.Length; i++) {
  995.                 while (paramOrder[i] != i) {
  996.                     int x = paramOrder[paramOrder[i]];
  997.                     object v = vars[paramOrder[i]];
  998.                    
  999.                     paramOrder[paramOrder[i]] = paramOrder[i];
  1000.                     vars[paramOrder[i]] = vars[i];
  1001.                    
  1002.                     paramOrder[i] = x;
  1003.                     vars[i] = v;
  1004.                 }
  1005.             }
  1006.         }
  1007.        
  1008.         // This method will create the mapping between the Parameters and the underlying
  1009.         // data based upon the names array. The names array is stored in the same order
  1010.         // as the values and maps to the parameters of the method. We store the mapping
  1011.         // from the parameters to the names in the paramOrder array. All parameters that
  1012.         // don't have matching names are then stored in the array in order.
  1013.         private static bool CreateParamOrder(int[] paramOrder, ParameterInfo[] pars, string[] names)
  1014.         {
  1015.             bool[] used = new bool[pars.Length];
  1016.            
  1017.             // Mark which parameters have not been found in the names list
  1018.             for (int i = 0; i < pars.Length; i++)
  1019.                 paramOrder[i] = -1;
  1020.             // Find the parameters with names.
  1021.             for (int i = 0; i < names.Length; i++) {
  1022.                 int j;
  1023.                 for (j = 0; j < pars.Length; j++) {
  1024.                     if (names[i].Equals(pars[j].Name)) {
  1025.                         paramOrder[j] = i;
  1026.                         used[i] = true;
  1027.                         break;
  1028.                     }
  1029.                 }
  1030.                 // This is an error condition. The name was not found. This
  1031.                 // method must not match what we sent.
  1032.                 if (j == pars.Length)
  1033.                     return false;
  1034.             }
  1035.            
  1036.             // Now we fill in the holes with the parameters that are unused.
  1037.             int pos = 0;
  1038.             for (int i = 0; i < pars.Length; i++) {
  1039.                 if (paramOrder[i] == -1) {
  1040.                     for (; pos < pars.Length; pos++) {
  1041.                         if (!used[pos]) {
  1042.                             paramOrder[i] = pos;
  1043.                             pos++;
  1044.                             break;
  1045.                         }
  1046.                     }
  1047.                 }
  1048.             }
  1049.             return true;
  1050.         }
  1051.        
  1052.         internal class BinderState
  1053.         {
  1054.             internal int[] m_argsMap;
  1055.             internal int m_originalSize;
  1056.             internal bool m_isParamArray;
  1057.            
  1058.             internal BinderState(int[] argsMap, int originalSize, bool isParamArray)
  1059.             {
  1060.                 m_argsMap = argsMap;
  1061.                 m_originalSize = originalSize;
  1062.                 m_isParamArray = isParamArray;
  1063.             }
  1064.            
  1065.         }
  1066.        
  1067.     }
  1068. }

Developer Fusion