// IVector.cs public interface IVector { int Size { get; } float this[int index] { get; set; } } // IMatrix.cs public interface IMatrix { int Size { get; } float this[int row,int column] { get; set; } }
以及这些接口的扩展方法
// VectorExtensions.cs public static T Add<T>(this T vector,T value) where T : struct,IVector { var output = default(T); for (int i = 0; i < output.Size; i++) output[i] = vector[i] + value[i]; return output; } // MatrixExtensions.cs public static T Add<T>(this T matrix,IMatrix { var output = default(T); for (int i = 0; i < output.Size; i++) for (int j = 0; j < output.Size; j++) output[i,j] = vector[i,j] + value[i,j]; return output; }
所有类型都在同一个命名空间中.
由于某些原因,当从IVector派生的东西调用Add()时,编译器无法确定是使用MatrixExtensions类还是VectorExtensions类中的定义.将其中一个扩展类移动到另一个命名空间停止错误…但是我希望它们在同一个命名空间中:D
为什么会发生这种情况?
解决方法
// VectorExtensions.cs public static T Add<T>(this T vector,T value) // MatrixExtensions.cs public static T Add<T>(this T matrix,T value)
是的,你在你的代码中提供了约束,但是constraints are not part of the signature.所以你有两个方法具有相同的签名,所以这两种方法都不比其他方法更好,而且你有歧义的问题.
将静态扩展方法类中的一个移动到不同的命名空间中的原因是不同的结果是编译器将在扩展搜索外部之前首先在最接近的包含命名空间中寻找扩展方法匹配. (参见C#语言规范的第7.5.5.2节[如下])如果将MatrixExtensions移动到另一个命名空间中,则原始命名空间内的扩展方法调用将明确地解析为VectorExtensions方法,因为它是最接近命名空间.但是,这并不能完全解决您的问题.因为如果它是最接近的扩展方法,因此您仍然可以使用这个VectorExtensions实现方法,因为再次约束不是签名的一部分.
为方便起见,语言规范.
7.5.5.2 Extension method invocations
In a method invocation (§7.5.5.1) of
one of the formsexpr . 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