64ac736ec5
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
181 lines
7.7 KiB
C#
181 lines
7.7 KiB
C#
using System.Reflection;
|
|
|
|
namespace System {
|
|
partial class DefaultBinder {
|
|
internal static bool CompareMethodSig (MethodBase m1, MethodBase m2)
|
|
{
|
|
ParameterInfo[] params1 = m1.GetParametersNoCopy ();
|
|
ParameterInfo[] params2 = m2.GetParametersNoCopy ();
|
|
|
|
if (params1.Length != params2.Length)
|
|
return false;
|
|
|
|
int numParams = params1.Length;
|
|
for (int i = 0; i < numParams; i++) {
|
|
if (params1 [i].ParameterType != params2 [i].ParameterType)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Given a set of methods that match the base criteria, select a method based
|
|
// upon an array of types. This method should return null if no method matchs
|
|
// the criteria.
|
|
public sealed override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
Type[] realTypes = new Type [types.Length];
|
|
for (i = 0; i < types.Length; i++)
|
|
{
|
|
realTypes[i] = types[i].UnderlyingSystemType;
|
|
if (!(realTypes[i].IsRuntimeImplemented() || realTypes[i] is SignatureType))
|
|
throw new ArgumentException(SR.Arg_MustBeType, nameof(types));
|
|
}
|
|
types = realTypes;
|
|
|
|
// We don't automatically jump out on exact match.
|
|
if (match == null || match.Length == 0)
|
|
throw new ArgumentException(SR.Arg_EmptyArray, nameof(match));
|
|
|
|
MethodBase[] candidates = (MethodBase[])match.Clone();
|
|
|
|
// Find all the methods that can be described by the types parameter.
|
|
// Remove all of them that cannot.
|
|
int CurIdx = 0;
|
|
for (i = 0; i < candidates.Length; i++)
|
|
{
|
|
ParameterInfo[] par = candidates[i].GetParametersNoCopy();
|
|
if (par.Length != types.Length)
|
|
continue;
|
|
for (j = 0; j < types.Length; j++)
|
|
{
|
|
Type pCls = par[j].ParameterType;
|
|
if (types[j].MatchesParameterTypeExactly(par[j]))
|
|
continue;
|
|
if (pCls == typeof(object))
|
|
continue;
|
|
|
|
Type type = types[j];
|
|
if (type is SignatureType signatureType)
|
|
{
|
|
if (!(candidates[i] is MethodInfo methodInfo))
|
|
break;
|
|
type = signatureType.TryResolveAgainstGenericMethod(methodInfo);
|
|
if (type == null)
|
|
break;
|
|
}
|
|
|
|
if (pCls.IsPrimitive)
|
|
{
|
|
if (!(type.UnderlyingSystemType.IsRuntimeImplemented()) ||
|
|
!CanChangePrimitive(type.UnderlyingSystemType, pCls.UnderlyingSystemType))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (!pCls.IsAssignableFrom(type))
|
|
break;
|
|
}
|
|
}
|
|
if (j == types.Length)
|
|
candidates[CurIdx++] = candidates[i];
|
|
}
|
|
if (CurIdx == 0)
|
|
return null;
|
|
if (CurIdx == 1)
|
|
return candidates[0];
|
|
|
|
// Walk all of the methods looking the most specific method to invoke
|
|
int currentMin = 0;
|
|
bool ambig = false;
|
|
int[] paramOrder = new int[types.Length];
|
|
for (i = 0; i < types.Length; i++)
|
|
paramOrder[i] = i;
|
|
for (i = 1; i < CurIdx; i++)
|
|
{
|
|
int newMin = FindMostSpecificMethod(candidates[currentMin], paramOrder, null, candidates[i], paramOrder, null, types, null);
|
|
if (newMin == 0)
|
|
ambig = true;
|
|
else
|
|
{
|
|
if (newMin == 2)
|
|
{
|
|
currentMin = i;
|
|
ambig = false;
|
|
currentMin = i;
|
|
}
|
|
}
|
|
}
|
|
if (ambig)
|
|
throw new AmbiguousMatchException(SR.Arg_AmbiguousMatchException);
|
|
return candidates[currentMin];
|
|
}
|
|
|
|
// CanChangePrimitive
|
|
// This will determine if the source can be converted to the target type
|
|
private static bool CanChangePrimitive(Type source, Type target)
|
|
{
|
|
return CanPrimitiveWiden(source, target);
|
|
}
|
|
|
|
// CanChangePrimitiveObjectToType
|
|
private static bool CanChangePrimitiveObjectToType(object source, Type type)
|
|
{
|
|
return CanPrimitiveWiden(source.GetType(), type);
|
|
}
|
|
|
|
private static bool CanPrimitiveWiden(Type source, Type target)
|
|
{
|
|
Primitives widerCodes = _primitiveConversions[(int)(Type.GetTypeCode(source))];
|
|
Primitives targetCode = (Primitives)(1 << (int)(Type.GetTypeCode(target)));
|
|
|
|
return 0 != (widerCodes & targetCode);
|
|
}
|
|
|
|
[Flags]
|
|
private enum Primitives
|
|
{
|
|
Boolean = 1 << (int)TypeCode.Boolean,
|
|
Char = 1 << (int)TypeCode.Char,
|
|
SByte = 1 << (int)TypeCode.SByte,
|
|
Byte = 1 << (int)TypeCode.Byte,
|
|
Int16 = 1 << (int)TypeCode.Int16,
|
|
UInt16 = 1 << (int)TypeCode.UInt16,
|
|
Int32 = 1 << (int)TypeCode.Int32,
|
|
UInt32 = 1 << (int)TypeCode.UInt32,
|
|
Int64 = 1 << (int)TypeCode.Int64,
|
|
UInt64 = 1 << (int)TypeCode.UInt64,
|
|
Single = 1 << (int)TypeCode.Single,
|
|
Double = 1 << (int)TypeCode.Double,
|
|
Decimal = 1 << (int)TypeCode.Decimal,
|
|
DateTime = 1 << (int)TypeCode.DateTime,
|
|
String = 1 << (int)TypeCode.String,
|
|
}
|
|
|
|
private static Primitives[] _primitiveConversions = new Primitives[]
|
|
{
|
|
/* Empty */ 0, // not primitive
|
|
/* Object */ 0, // not primitive
|
|
/* DBNull */ 0, // not exposed.
|
|
/* Boolean */ Primitives.Boolean,
|
|
/* Char */ Primitives.Char | Primitives.UInt16 | Primitives.UInt32 | Primitives.Int32 | Primitives.UInt64 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* SByte */ Primitives.SByte | Primitives.Int16 | Primitives.Int32 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* Byte */ Primitives.Byte | Primitives.Char | Primitives.UInt16 | Primitives.Int16 | Primitives.UInt32 | Primitives.Int32 | Primitives.UInt64 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* Int16 */ Primitives.Int16 | Primitives.Int32 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* UInt16 */ Primitives.UInt16 | Primitives.UInt32 | Primitives.Int32 | Primitives.UInt64 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* Int32 */ Primitives.Int32 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* UInt32 */ Primitives.UInt32 | Primitives.UInt64 | Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* Int64 */ Primitives.Int64 | Primitives.Single | Primitives.Double,
|
|
/* UInt64 */ Primitives.UInt64 | Primitives.Single | Primitives.Double,
|
|
/* Single */ Primitives.Single | Primitives.Double,
|
|
/* Double */ Primitives.Double,
|
|
/* Decimal */ Primitives.Decimal,
|
|
/* DateTime */ Primitives.DateTime,
|
|
/* [Unused] */ 0,
|
|
/* String */ Primitives.String,
|
|
};
|
|
}
|
|
} |