Add information to what is ambiguously matched when an AmbiguousMatchException is thrown as we know what we found multiple matching items for.
Renames of SR/RESX strings. Removal of `.ToString()` calls. Remove unused strings from RESX RESX string rewording.
Change the exception format string to "found for" style.
Cleanup of DefaultBinder.cs FindMostDerived* to use the local variable.
Remove copy-pasta ThrowHelper.cs instance.
Don't emit the CustomAtrributeData's type
All MemberInfo cases pass a (possibly null) `DeclaringType`.
Co-authored-by: Buyaa Namnan <buyankhishig.namnan@microsoft.com>
if (attrib == null || attrib.Length == 0)
return null;
+ Attribute match = attrib[0];
if (attrib.Length == 1)
- return attrib[0];
+ return match;
- throw new AmbiguousMatchException(SR.RFLCT_AmbigCust);
+ throw ThrowHelper.GetAmbiguousMatchException(match);
}
#endregion
if (attrib == null || attrib.Length == 0)
return null;
+ Attribute match = attrib[0];
if (attrib.Length == 1)
- return attrib[0];
+ return match;
- throw new AmbiguousMatchException(SR.RFLCT_AmbigCust);
+ throw ThrowHelper.GetAmbiguousMatchException(match);
}
#endregion
if (attrib == null || attrib.Length == 0)
return null;
+ Attribute match = attrib[0];
if (attrib.Length == 1)
- return attrib[0];
+ return match;
- throw new AmbiguousMatchException(SR.RFLCT_AmbigCust);
+ throw ThrowHelper.GetAmbiguousMatchException(match);
}
#endregion
if (attrib == null || attrib.Length == 0)
return null;
+ Attribute match = attrib[0];
if (attrib.Length == 1)
- return attrib[0];
+ return match;
- throw new AmbiguousMatchException(SR.RFLCT_AmbigCust);
+ throw ThrowHelper.GetAmbiguousMatchException(match);
}
#endregion
{
MethodInfo methodInfo = candidates[j];
if (!System.DefaultBinder.CompareMethodSig(methodInfo, firstCandidate))
- {
- throw new AmbiguousMatchException();
- }
+ throw ThrowHelper.GetAmbiguousMatchException(firstCandidate);
}
// All the methods have the exact same name and sig so return the most derived one.
if (types == null || types.Length == 0)
{
// no arguments
+ PropertyInfo firstCandidate = candidates[0];
+
if (candidates.Count == 1)
{
- PropertyInfo firstCandidate = candidates[0];
-
if (returnType is not null && !returnType.IsEquivalentTo(firstCandidate.PropertyType))
return null;
{
if (returnType is null)
// if we are here we have no args or property type to select over and we have more than one property with that name
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(firstCandidate);
}
}
if ((bindingAttr & eventInfo.BindingFlags) == eventInfo.BindingFlags)
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = eventInfo;
}
if (match != null)
{
if (ReferenceEquals(fieldInfo.DeclaringType, match.DeclaringType))
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
if ((match.DeclaringType!.IsInterface) && (fieldInfo.DeclaringType!.IsInterface))
multipleStaticFieldMatches = true;
}
if (multipleStaticFieldMatches && match!.DeclaringType!.IsInterface)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
return match;
}
if (FilterApplyType(iface, bindingAttr, name, false, ns))
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = iface;
}
if (FilterApplyType(nestedType, bindingAttr, name, false, ns))
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = nestedType;
}
return null;
CustomAttributeData result = enumerator.Current;
if (enumerator.MoveNext())
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(result);
return result.Instantiate();
}
// Assuming the policy says it's ok to ignore the ambiguity, we're to resolve in favor of the member
// declared by the most derived type. Since QueriedMemberLists are sorted in order of decreasing derivation,
// that means we let the first match win - unless, of course, they're both the "most derived member".
- if (match.DeclaringType.Equals(challenger.DeclaringType))
- throw new AmbiguousMatchException();
-
- if (!_policies.OkToIgnoreAmbiguity(match, challenger))
- throw new AmbiguousMatchException();
+ // If they're not from same type, we throw if the policy doesn't allow ambiguity.
+ if (match.DeclaringType.Equals(challenger.DeclaringType) ||
+ !_policies.OkToIgnoreAmbiguity(match, challenger))
+ throw ThrowHelper.GetAmbiguousMatchException(match);
}
else
{
if (ns != null && !ns.Equals(ifc.Namespace))
continue;
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = ifc;
}
return match;
if (types == null || types.Length == 0)
{
// no arguments
+ PropertyInfo firstCandidate = candidates[0];
+
if (candidates.Count == 1)
{
- PropertyInfo firstCandidate = candidates[0];
if (returnType is not null && !returnType.IsEquivalentTo(firstCandidate.PropertyType))
return null;
return firstCandidate;
else
{
if (returnType is null)
+ {
// if we are here we have no args or property type to select over and we have more than one property with that name
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(firstCandidate);
+ }
}
}
{
if (foundMatch)
{
- exception = new AmbiguousMatchException();
+ exception = new AmbiguousMatchException(SR.Format(SR.AmbiguousMatchException_Assembly, refName.FullName));
return false;
}
<?xml version="1.0" encoding="utf-8"?>
<root>
- <!--
- Microsoft ResX Schema
-
+ <!--
+ Microsoft ResX Schema
+
Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
associated with the data types.
-
+
Example:
-
+
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
-
- There are any number of "resheader" rows that contain simple
+
+ There are any number of "resheader" rows that contain simple
name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
-
+
mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
-
+
mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
+ value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<data name="FileLoadException_RefDefMismatch" xml:space="preserve">
<value>Cannot load assembly '{0}'. The assembly exists but its version {1} is lower than the requested version {2}.</value>
</data>
+ <data name="AmbiguousMatchException_Assembly" xml:space="preserve">
+ <value>Ambiguous match found for assembly '{0}'.</value>
+ </data>
</root>
<data name="AppDomain_Policy_PrincipalTwice" xml:space="preserve">
<value>Default principal object cannot be set twice.</value>
</data>
- <data name="AmbiguousImplementationException_NullMessage" xml:space="preserve">
- <value>Ambiguous implementation found.</value>
- </data>
<data name="Arg_AccessException" xml:space="preserve">
<value>Cannot access member.</value>
</data>
<data name="Arg_AccessViolationException" xml:space="preserve">
<value>Attempted to read or write protected memory. This is often an indication that other memory is corrupt.</value>
</data>
- <data name="Arg_AmbiguousMatchException" xml:space="preserve">
+ <data name="Arg_AmbiguousImplementationException_NoMessage" xml:space="preserve">
+ <value>Ambiguous implementation found.</value>
+ </data>
+ <data name="Arg_AmbiguousMatchException_Attribute" xml:space="preserve">
+ <value>Multiple custom attributes of the same type '{0}' found.</value>
+ </data>
+ <data name="Arg_AmbiguousMatchException_NoMessage" xml:space="preserve">
<value>Ambiguous match found.</value>
</data>
+ <data name="Arg_AmbiguousMatchException_CustomAttributeData" xml:space="preserve">
+ <value>Ambiguous match found for '{0}'.</value>
+ </data>
+ <data name="Arg_AmbiguousMatchException_MemberInfo" xml:space="preserve">
+ <value>Ambiguous match found for '{0} {1}'.</value>
+ </data>
<data name="Arg_ApplicationException" xml:space="preserve">
<value>Error in the application.</value>
</data>
<data name="Resources_StreamNotValid" xml:space="preserve">
<value>Stream is not a valid resource file.</value>
</data>
- <data name="RFLCT_AmbigCust" xml:space="preserve">
- <value>Multiple custom attributes of the same type found.</value>
- </data>
<data name="InvalidFilterCriteriaException_CritInt" xml:space="preserve">
<value>An Int32 must be provided for the filter criteria.</value>
</data>
#endregion
}
+ MethodBase bestMatch = candidates[currentMin]!;
+
if (ambig)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
// Reorder (if needed)
if (names != null)
// If the parameters and the args are not the same length or there is a paramArray
// then we need to create a argument array.
- ParameterInfo[] parameters = candidates[currentMin]!.GetParametersNoCopy();
+ ParameterInfo[] parameters = bestMatch.GetParametersNoCopy();
if (parameters.Length == args.Length)
{
if (paramArrayTypes[currentMin] != null)
}
else
{
- if ((candidates[currentMin]!.CallingConvention & CallingConventions.VarArgs) == 0)
+ if ((bestMatch.CallingConvention & CallingConventions.VarArgs) == 0)
{
object[] objs = new object[parameters.Length];
int paramArrayPos = parameters.Length - 1;
}
}
- return candidates[currentMin]!;
+ return bestMatch;
}
// Given a set of fields that match the base criteria, select a field.
}
}
}
+ FieldInfo bestMatch = candidates[currentMin];
if (ambig)
- throw new AmbiguousMatchException();
- return candidates[currentMin];
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
+ return bestMatch;
}
// Given a set of methods that match the base criteria, select a method based
}
}
}
+ MethodBase bestMatch = candidates[currentMin];
if (ambig)
- throw new AmbiguousMatchException();
- return candidates[currentMin];
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
+ return bestMatch;
}
// Given a set of properties that match the base criteria, select one.
currentMin = i;
}
}
-
+ PropertyInfo bestMatch = candidates[currentMin];
if (ambig)
- throw new AmbiguousMatchException();
- return candidates[currentMin];
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
+ return bestMatch;
}
// ChangeType
continue;
if (bestMatch != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
bestMatch = match[i];
}
// This can only happen if at least one is vararg or generic.
if (currentHierarchyDepth == deepestHierarchy)
{
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(methWithDeepestHierarchy!);
}
// Check to see if this method is on the most derived class.
public sealed class AmbiguousMatchException : SystemException
{
public AmbiguousMatchException()
- : base(SR.Arg_AmbiguousMatchException)
+ : base(SR.Arg_AmbiguousMatchException_NoMessage)
{
HResult = HResults.COR_E_AMBIGUOUSMATCH;
}
public sealed class AmbiguousImplementationException : Exception
{
public AmbiguousImplementationException()
- : base(SR.AmbiguousImplementationException_NullMessage)
+ : base(SR.Arg_AmbiguousImplementationException_NoMessage)
{
HResult = HResults.COR_E_AMBIGUOUSIMPLEMENTATION;
}
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Numerics;
+using System.Reflection;
+using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
throw new FormatException(SR.Format_IndexOutOfRange);
}
+ internal static AmbiguousMatchException GetAmbiguousMatchException(MemberInfo memberInfo)
+ {
+ Type? declaringType = memberInfo.DeclaringType;
+ return new AmbiguousMatchException(SR.Format(SR.Arg_AmbiguousMatchException_MemberInfo, declaringType, memberInfo));
+ }
+
+ internal static AmbiguousMatchException GetAmbiguousMatchException(Attribute attribute)
+ {
+ return new AmbiguousMatchException(SR.Format(SR.Arg_AmbiguousMatchException_Attribute, attribute));
+ }
+
+ internal static AmbiguousMatchException GetAmbiguousMatchException(CustomAttributeData customAttributeData)
+ {
+ return new AmbiguousMatchException(SR.Format(SR.Arg_AmbiguousMatchException_CustomAttributeData, customAttributeData));
+ }
+
private static Exception GetArraySegmentCtorValidationFailedException(Array? array, int offset, int count)
{
if (array == null)
<data name="Argument_ObjectArgumentMismatch" xml:space="preserve">
<value>Object of type '{0}' cannot be converted to type '{1}'.</value>
</data>
-</root>
\ No newline at end of file
+ <data name="Arg_AmbiguousMatchException_MemberInfo" xml:space="preserve">
+ <value>Ambiguous match found for '{0} {1}'.</value>
+ </data>
+</root>
}
}
-
if (matchingMethods.Count == 0)
return null;
Debug.Assert(types == null || types.Length == 0);
// matches any signature
+ MethodInfo match = matchingMethods[0];
if (matchingMethods.Count == 1)
- return matchingMethods[0];
- else
- throw new AmbiguousMatchException();
+ return match;
+
+ Type? declaringType = match.DeclaringType;
+ throw new AmbiguousMatchException(SR.Format(SR.Arg_AmbiguousMatchException_MemberInfo, declaringType, match));
}
else
{
<data name="Arg_InvalidPath" xml:space="preserve">
<value>The path '{0}' is not valid.</value>
</data>
-</root>
\ No newline at end of file
+ <data name="Arg_AmbiguousMatchException_RoDefinitionType" xml:space="preserve">
+ <value>Ambiguous match found for '{0}'.</value>
+ </data>
+ <data name="Arg_AmbiguousMatchException_MemberInfo" xml:space="preserve">
+ <value>Ambiguous match found for '{0} {1}'.</value>
+ </data>
+</root>
<Compile Include="System\Reflection\TypeLoading\Types\RoType.TypeClassification.cs" />
<Compile Include="System\Reflection\TypeLoading\Types\RoWrappedType.cs" />
<Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
+ <Compile Include="System\ThrowHelper.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
ambig = false;
}
}
+ MethodBase bestMatch = candidates[currentMin];
if (ambig)
- throw new AmbiguousMatchException();
- return candidates[currentMin];
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
+ return bestMatch;
}
// Given a set of properties that match the base criteria, select one.
}
}
+ PropertyInfo bestMatch = candidates[currentMin];
if (ambig)
- throw new AmbiguousMatchException();
- return candidates[currentMin];
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
+ return bestMatch;
}
// The default binder doesn't support any change type functionality.
continue;
if (bestMatch != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(bestMatch);
bestMatch = match[i];
}
// This can only happen if at least one is vararg or generic.
if (currentHierarchyDepth == deepestHierarchy)
{
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(methWithDeepestHierarchy!);
}
// Check to see if this method is on the most derived class.
// declared by the most derived type. Since QueriedMemberLists are sorted in order of decreasing derivation,
// that means we let the first match win - unless, of course, they're both the "most derived member".
if (match.DeclaringType!.Equals(challenger.DeclaringType))
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
MemberPolicies<M> policies = MemberPolicies<M>.Default;
if (!policies.OkToIgnoreAmbiguity(match, challenger))
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
}
else
{
MemberInfo[] members = attributeType.GetMember(name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance);
if (members.Length == 0)
throw new MissingMemberException(attributeType.FullName, name);
+ MemberInfo match = members[0];
if (members.Length > 1)
- throw new AmbiguousMatchException();
-
- return new CustomAttributeNamedArgument(members[0], new CustomAttributeTypedArgument(argumentType!, value));
+ throw ThrowHelper.GetAmbiguousMatchException(match);
+ return new CustomAttributeNamedArgument(match, new CustomAttributeTypedArgument(argumentType!, value));
}
/// <summary>
// For perf and .NET Framework compat, fast-path these specific checks before calling on the binder to break ties.
if (types == null || types.Length == 0)
{
+ PropertyInfo firstCandidate = candidates[0];
+
// no arguments
if (candidates.Count == 1)
{
- PropertyInfo firstCandidate = candidates[0];
if (!(returnType is null) && !returnType.IsEquivalentTo(firstCandidate.PropertyType))
return null;
return firstCandidate;
{
if (returnType is null)
// if we are here we have no args or property type to select over and we have more than one property with that name
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(firstCandidate);
}
}
if (nestedTypeDefinition.Name.Equals(utf8Name, reader))
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = handle.ResolveTypeDef(GetEcmaModule());
}
}
if (ns.Length != 0 && !ns.Equals(ifc.Namespace))
continue;
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = ifc;
}
return match;
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This file defines an internal static class used to throw exceptions in the
+// the System.Reflection.MetadataLoadContext code.
+
+using System.Reflection;
+using System.Reflection.TypeLoading;
+
+namespace System
+{
+ internal static class ThrowHelper
+ {
+ internal static AmbiguousMatchException GetAmbiguousMatchException(RoDefinitionType roDefinitionType)
+ {
+ return new AmbiguousMatchException(SR.Format(SR.Arg_AmbiguousMatchException_RoDefinitionType, roDefinitionType.FullName));
+ }
+
+ internal static AmbiguousMatchException GetAmbiguousMatchException(MemberInfo memberInfo)
+ {
+ Type? declaringType = memberInfo.DeclaringType;
+ return new AmbiguousMatchException(SR.Format(SR.Arg_AmbiguousMatchException_MemberInfo, declaringType, memberInfo));
+ }
+ }
+}
<value>Event invocation for COM objects requires the declaring interface of the event to be attributed with ComEventInterfaceAttribute.</value>
</data>
<data name="AmbiguousMatch_MultipleEventInterfaceAttributes" xml:space="preserve">
- <value>More than one ComEventInterfaceAttribute was found on the declaring interface of the event.</value>
+ <value>More than one ComEventInterfaceAttribute found for '{0}' on the declaring interface of the event.</value>
</data>
<data name="InvalidOperation_NoDispIdAttribute" xml:space="preserve">
<value>Event invocation for COM objects requires event to be attributed with DispIdAttribute.</value>
throw new InvalidOperationException(SR.InvalidOperation_NoComEventInterfaceAttribute);
}
+ ComEventInterfaceAttribute interfaceAttribute = (ComEventInterfaceAttribute)comEventInterfaces[0];
+
if (comEventInterfaces.Length > 1)
{
- throw new AmbiguousMatchException(SR.AmbiguousMatch_MultipleEventInterfaceAttributes);
+ throw new AmbiguousMatchException(SR.Format(SR.AmbiguousMatch_MultipleEventInterfaceAttributes, interfaceAttribute));
}
- Type sourceInterface = ((ComEventInterfaceAttribute)comEventInterfaces[0]).SourceInterface;
+ Type sourceInterface = interfaceAttribute.SourceInterface;
Guid guid = sourceInterface.GUID;
-
MethodInfo methodInfo = sourceInterface.GetMethod(eventInfo.Name)!;
Attribute? dispIdAttribute = Attribute.GetCustomAttribute(methodInfo, typeof(DispIdAttribute));
if (dispIdAttribute == null)
object[] attrs = CustomAttribute.GetCustomAttributes(element, attributeType, inherit);
if (attrs == null || attrs.Length == 0)
return null;
+ Attribute match = (Attribute)attrs[0];
if (attrs.Length != 1)
- throw new AmbiguousMatchException();
- return (Attribute)(attrs[0]);
+ throw ThrowHelper.GetAmbiguousMatchException(match);
+ return match;
}
public static Attribute? GetCustomAttribute(Assembly element, Type attributeType) => GetAttr(element, attributeType, true);
if (types == null)
{
if (count > 1)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(found!);
return found;
}
MethodBase[] match = new MethodBase[count];
{
MethodInfo methodInfo = candidates[j];
if (!System.DefaultBinder.CompareMethodSig(methodInfo, firstCandidate))
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(firstCandidate);
}
// All the methods have the exact same name and sig so return the most derived one.
if (types == null || types.Length == 0)
{
// no arguments
+ PropertyInfo firstCandidate = candidates[0];
+
if (candidates.Count == 1)
{
- PropertyInfo firstCandidate = candidates[0];
-
if (returnType is not null && !returnType.IsEquivalentTo(firstCandidate.PropertyType))
return null;
{
if (returnType is null)
// if we are here we have no args or property type to select over and we have more than one property with that name
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(firstCandidate);
}
}
if ((bindingAttr & eventInfo.BindingFlags) == eventInfo.BindingFlags)
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = eventInfo;
}
if (match != null)
{
if (ReferenceEquals(fieldInfo.DeclaringType, match.DeclaringType))
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
if (match.DeclaringType!.IsInterface && fieldInfo.DeclaringType!.IsInterface)
multipleStaticFieldMatches = true;
}
if (multipleStaticFieldMatches && match!.DeclaringType!.IsInterface)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
return match;
}
if (FilterApplyType(iface, bindingAttr, name, false, ns))
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = iface;
}
if (FilterApplyType(nestedType, bindingAttr, name, false, ns))
{
if (match != null)
- throw new AmbiguousMatchException();
+ throw ThrowHelper.GetAmbiguousMatchException(match);
match = nestedType;
}