c# – 泛型扩展方法歧义

我有两个接口定义:
// 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 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

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...