private static void EvaluateCandidate(List<CandidateMember> candidates, MemberInfo candidateMember, ParameterInfo[] parameters, List<Argument> arguments, out ValidationError error, BuildArgCountMismatchError buildArgCountMismatchError) { error = null; int numArguments = arguments.Count; string candidateName = candidateMember.Name; if (parameters == null || parameters.Length == 0) { // If there were no arguments supplied, and this method has no parameters, // then it's a candidate. (It should be the only one.) if (numArguments == 0) { candidates.Add(new CandidateMember(candidateMember)); } else { error = buildArgCountMismatchError(candidateName, numArguments); } } else { List<CandidateParameter> signature = new List<CandidateParameter>(); int parameterCount = parameters.Length; int fixedParameterCount = parameterCount; // Check to see if the last parameter is (1) an array and (2) has a ParamArrayAttribute // (i.e., it is a "params" array). ParameterInfo lastParam = parameters[parameterCount - 1]; if (lastParam.ParameterType.IsArray) { object[] attrs = lastParam.GetCustomAttributes(typeof(ParamArrayAttribute), false); if (attrs != null && attrs.Length > 0) fixedParameterCount -= 1; } if (numArguments < fixedParameterCount) { // Not enough arguments were passed for this to be a candidate. error = buildArgCountMismatchError(candidateName, numArguments); return; } else if (fixedParameterCount == parameterCount && numArguments != parameterCount) { // Too many arguments were passed for this to be a candidate. error = buildArgCountMismatchError(candidateName, numArguments); return; } // For the fixed part of the method signature, make sure each argument can // be implicitly converted to the corresponding parameter. int p = 0; for (; p < fixedParameterCount; ++p) { CandidateParameter candidateParam = new CandidateParameter(parameters[p]); if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error)) break; // argument #p didn't match // If we get here, then so far so good. signature.Add(candidateParam); } if (p != fixedParameterCount) { // We didn't match all of the fixed part. This method is not a candidate. return; } if (fixedParameterCount < parameterCount) { // The last parameter was a "params" array. As long as zero or more arguments // are assignable, it's a valid candidate in the expanded form. CandidateMember candidateMethod = null; if (numArguments == fixedParameterCount) { // Zero arguments were passed as the params array. The method is a candidate // in its expanded form. candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded); } else if (numArguments == parameterCount) { // Special case: one argument was passed as the params array. CandidateParameter candidateParam = new CandidateParameter(lastParam); if (candidateParam.Match(arguments[p], candidateName, p + 1, out error)) { // It was the same array type as the params array, so the candidate // matched in its normal form. signature.Add(candidateParam); candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal); } } if (candidateMethod == null) { // One or more arguments were passed as the params array. As long // as they match the element type, this method is a candidate. CandidateParameter candidateParam = new CandidateParameter(lastParam.ParameterType.GetElementType()); for (; p < numArguments; ++p) { if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error)) { // Not all of the trailing arguments matched the params array's element type; // this cannot be a candidate. return; } // If we get here, then so far so good. signature.Add(candidateParam); } // All the trailing arguments matched, so this is a candidate in the expanded form. candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded); } candidates.Add(candidateMethod); } else { // The last parameter wasn't "params". This candidate matched in its normal form. candidates.Add(new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal)); } } }
private static void EvaluateCandidate(List<CandidateMember> candidates, MemberInfo candidateMember, ParameterInfo[] parameters, List<Argument> arguments, out ValidationError error, BuildArgCountMismatchError buildArgCountMismatchError) { error = null; int count = arguments.Count; string name = candidateMember.Name; if ((parameters == null) || (parameters.Length == 0)) { if (count == 0) { candidates.Add(new CandidateMember(candidateMember)); } else { error = buildArgCountMismatchError(name, count); } } else { List<CandidateParameter> signature = new List<CandidateParameter>(); int length = parameters.Length; int num3 = length; ParameterInfo paramInfo = parameters[length - 1]; if (paramInfo.ParameterType.IsArray) { object[] customAttributes = paramInfo.GetCustomAttributes(typeof(ParamArrayAttribute), false); if ((customAttributes != null) && (customAttributes.Length > 0)) { num3--; } } if (count < num3) { error = buildArgCountMismatchError(name, count); } else if ((num3 == length) && (count != length)) { error = buildArgCountMismatchError(name, count); } else { int index = 0; while (index < num3) { CandidateParameter item = new CandidateParameter(parameters[index]); if (!item.Match(arguments[index], name, index + 1, out error)) { break; } signature.Add(item); index++; } if (index == num3) { if (num3 < length) { CandidateMember member = null; if (count == num3) { member = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded); } else if (count == length) { CandidateParameter parameter2 = new CandidateParameter(paramInfo); if (parameter2.Match(arguments[index], name, index + 1, out error)) { signature.Add(parameter2); member = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal); } } if (member == null) { CandidateParameter parameter3 = new CandidateParameter(paramInfo.ParameterType.GetElementType()); while (index < count) { if (!parameter3.Match(arguments[index], name, index + 1, out error)) { return; } signature.Add(parameter3); index++; } member = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded); } candidates.Add(member); } else { candidates.Add(new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal)); } } } } }
internal int CompareMember(Type targetType, CandidateMember other, List<Argument> arguments, RuleValidation validator) { int better = 1; int worse = -1; int equal = 0; // Methods in a base class are not candidates if any method in a derived class // is applicable. Type thisDeclaringType = this.Member.DeclaringType; Type otherDeclaringType = other.Member.DeclaringType; if (thisDeclaringType != otherDeclaringType) { if (TypeProvider.IsAssignable(otherDeclaringType, thisDeclaringType)) { // This declaring type can be converted to the other declaring type, // which means this one is more derived. return better; } else if (TypeProvider.IsAssignable(thisDeclaringType, otherDeclaringType)) { // The other declaring type can be converted to this declaring type, // which means the other one is more derived. return worse; } } System.Diagnostics.Debug.Assert(arguments.Count == this.signature.Count); System.Diagnostics.Debug.Assert(arguments.Count == other.signature.Count); bool hasAtLeastOneBetterConversion = false; bool hasAtLeastOneWorseConversion = false; bool signaturesAreIdentical = true; // pick non-extension methods over extension methods // if both are extension methods, then pick the one in the namespace closest to "this" ExtensionMethodInfo thisExtension = this.Member as ExtensionMethodInfo; ExtensionMethodInfo otherExtension = other.Member as ExtensionMethodInfo; if ((thisExtension == null) && (otherExtension != null)) return better; else if ((thisExtension != null) && (otherExtension == null)) return worse; else if ((thisExtension != null) && (otherExtension != null)) { // we have 2 extension methods, which one is better string[] thisNameSpace = thisExtension.DeclaringType.FullName.Split('.'); string[] otherNameSpace = otherExtension.DeclaringType.FullName.Split('.'); string[] bestNameSpace = validator.thisType.FullName.Split('.'); int thisMatch = MatchNameSpace(thisNameSpace, bestNameSpace); int otherMatch = MatchNameSpace(otherNameSpace, bestNameSpace); if (thisMatch > otherMatch) return better; else if (thisMatch < otherMatch) return worse; // compare arguments, including the "this" argument CandidateParameter thisDeclaringParam = new CandidateParameter(thisExtension.AssumedDeclaringType); CandidateParameter otherDeclaringParam = new CandidateParameter(otherExtension.AssumedDeclaringType); if (!thisDeclaringParam.Equals(otherDeclaringParam)) { signaturesAreIdentical = false; int conversionResult = thisDeclaringParam.CompareConversion(otherDeclaringParam, new Argument(targetType)); if (conversionResult < 0) { // A conversion was found that was worse, so this candidate is not better. hasAtLeastOneWorseConversion = true; } else if (conversionResult > 0) { // This candidate had at least one conversion that was better. (But // we have to keep looking in case there's one that's worse.) hasAtLeastOneBetterConversion = true; } } // this check compares parameter lists correctly (see below) for (int p = 0; p < arguments.Count; ++p) { CandidateParameter thisParam = this.signature[p]; CandidateParameter otherParam = other.signature[p]; if (!thisParam.Equals(otherParam)) signaturesAreIdentical = false; int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]); if (conversionResult < 0) { // A conversion was found that was worse, so this candidate is not better. hasAtLeastOneWorseConversion = true; } else if (conversionResult > 0) { // This candidate had at least one conversion that was better. (But // we have to keep looking in case there's one that's worse.) hasAtLeastOneBetterConversion = true; } } if (hasAtLeastOneBetterConversion && !hasAtLeastOneWorseConversion) { // At least one conversion was better than the "other" candidate // and no other arguments were worse, so this one is better. return better; } else if (!hasAtLeastOneBetterConversion && hasAtLeastOneWorseConversion) { // At least one conversion was worse than the "other" candidate // and no other arguments were better, so this one is worse. return worse; } } else { // NOTE: this is the original v1 code // It doesn't check for worse parameters correctly. // However, for backwards compatability, we can't change it for (int p = 0; p < arguments.Count; ++p) { CandidateParameter thisParam = this.signature[p]; CandidateParameter otherParam = other.signature[p]; if (!thisParam.Equals(otherParam)) signaturesAreIdentical = false; int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]); if (conversionResult < 0) { // A conversion was found that was worse, so this candidate is not better. return worse; } else if (conversionResult > 0) { // This candidate had at least one conversion that was better. (But // we have to keep looking in case there's one that's worse.) hasAtLeastOneBetterConversion = true; } } if (hasAtLeastOneBetterConversion) { // At least one conversion was better than the "other" candidate, so this one // is better. return better; } } if (signaturesAreIdentical) { // The signatures were "tied". Try some disambiguating rules for expanded signatures // vs normal signatures. if (this.form == Form.Normal && other.form == Form.Expanded) { // This candidate matched in its normal form, but the other one matched only after // expansion of a params array. This one is better. return better; } else if (this.form == Form.Expanded && other.form == Form.Normal) { // This candidate matched in its expanded form, but the other one matched in its // normal form. The other one was better. return worse; } else if (this.form == Form.Expanded && other.form == Form.Expanded) { // Both candidates matched in their expanded forms. int thisParameterCount = this.memberParameters.Length; int otherParameterCount = other.memberParameters.Length; if (thisParameterCount > otherParameterCount) { // This candidate had more declared parameters, so it is better. return better; } else if (otherParameterCount > thisParameterCount) { // The other candidate had more declared parameters, so it was better. return worse; } } } // Nothing worked, the two candidates are equally applicable. return equal; }