122
}
class MethodData
{
public MethodBase MethodBase;
public ParameterInfo[] Parameters;
public Expression[] Args;
}
int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase
method) {
MethodData[] applicable = methods.
Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).
Where(m => IsApplicable(m, args)).
ToArray();
if (applicable.Length > 1) {
applicable = applicable.
Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
ToArray();
}
if (applicable.Length == 1) {
MethodData md = applicable[0];
for (int i = 0; i < args.Length; i++) args[i] = md.Args[i];
method = md.MethodBase;
}
else {
method = null;
}
return applicable.Length;
}
bool IsApplicable(MethodData method, Expression[] args) {
if (method.Parameters.Length != args.Length) return false;
Expression[] promotedArgs = new Expression[args.Length];
for (int i = 0; i < args.Length; i++) {
ParameterInfo pi = method.Parameters[i];
if (pi.IsOut) return false;
Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
if (promoted == null) return false;
promotedArgs[i] = promoted;
}
method.Args = promotedArgs;
return true;
}
Expression PromoteExpression(Expression expr, Type type, bool exact) {
if (expr.Type == type) return expr;
if (expr is ConstantExpression) {
ConstantExpression ce = (ConstantExpression)expr;
if (ce == nullLiteral) {
if (!type.IsValueType || IsNullableType(type))
return Expression.Constant(null, type);
}
else {
string text;
if (literals.TryGetValue(ce, out text)) {
Type target = GetNonNullableType(type);