I have two interfaces defined:
// IVector.cs
public interface IVector
{
int Size { get; }
float this[int index] { get; set; }
}
// IMatrix.cs
publi
You have two extension method that each have the same signature.
// VectorExtensions.cs
public static T Add(this T vector, T value)
// MatrixExtensions.cs
public static T Add(this T matrix, T value)
Yes, you have provided constraints in your code, but constraints are not part of the signature. So you have two method with the same signature, neither method is therefore better than the other, and you have an ambiguity problem.
The reason why moving one of the static extension method classes into a different namespace has a different result is that the compiler will look for extension method matches first within the closest containing namespace before expanding the search outward. (See: Section 7.5.5.2 [below] of the C# language specification.) If you move MatrixExtensions, for example, into a different namespace, now extension method invocations inside the original namespace will unambiguously resolve to the VectorExtensions method, as it is the closest in terms of namespaces. However, this doesn't completely resolve your problem. Because you could still have IMatrix trying to use the VectorExtensions implementation if it's the closest extension method because, again, constraints are not part of the signature.
For your convenience, the language specification.
7.5.5.2 Extension method invocations
In a method invocation (§7.5.5.1) of one of the forms
expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )
if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. The objective is to find the best type-name C, so that the corresponding static method invocation can take place:
C . identifier ( expr )
C . identifier ( expr , args )
C . identifier < typeargs > ( expr )
C . identifier < typeargs > ( expr , args )
The search for C proceeds as follows:
- Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods:
- If the given namespace or compilation unit directly contains non-generic type declarations Ci with extension methods Mj that have the name identifier and are accessible and applicable with respect to the desired static method invocation above, then the set of those extension methods is the candidate set.
- If namespaces imported by using namespace directives in the given namespace or compilation unit directly contain non-generic type declarations Ci with extension methods Mj that have the name identifier and are accessible and applicable with respect to the desired static method invocation above, then the set of those extension methods is the candidate set.
- If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs.
- Otherwise, overload resolution is applied to the candidate set as described in (§7.4.3). If no single best method is found, a compile-time error occurs.
- C is the type within which the best method is declared as an extension method. Using C as a target, the method call is then processed as a static method invocation (§7.4.4). The preceding rules mean that instance methods take precedence over extension methods, that extension methods available in inner namespace declarations take precedence over extension methods available in outer namespace declarations, and that extension methods declared directly in a namespace take precedence over extension methods imported into that same namespace with a using namespace directive