6

下面是 C# 4.0 控制台程序的简单代码:

using System.DirectoryServices.Protocols;
namespace OverloadTest
{
  class Program
  {
    static void Main(string[] args)
    {
      var request = new SearchRequest("", "", SearchScope.Base, null);
    }
  }
}

SearchRequest 有3 个构造函数;对于此示例,只有带 4 个参数的两个重要:

在这两个构造函数之间,它们的第一个、第三个和第四个参数具有相同类型和命名的参数。只有第二个参数不同:字符串 ldapFilterXmlDocument filter

对我来说,上面的代码显然是调用构造函数,它的第二个参数声明为:string ldapFilter

但是,如果此代码所在的项目没有对System.XML的引用,则编译会导致以下错误:
“System.Xml.XmlDocument”类型是在未引用的程序集中定义的。您必须添加对程序集 'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' 的引用

显然,编译器无法评估要使用哪个重载,因为错误的重载具有由于缺少对声明组件的引用而无法理解的类型的参数。当然,编译器必须找到一个“最佳方法”来匹配我的代码,但是由于我的第二个传递参数是一个字符串,为什么编译器需要担心将我的代码与XmlDocument重载匹配?或者,作为 System.DirectoryServices.Protocols.SearchRequest 使用 XmlDocument 类型(作为构造函数参数类型);为什么编译器还没有足够了解 XmlDocument 是什么来确定一个字符串不是一个字符串,从而能够选择正确的重载?

我已经有两个解决方法可以编译没有错误:

  1. 在项目中添加对 System.XML 的引用。

  2. 命名第二个参数(因此也必须命名第三个和第四个),如下所示:

    var request = new SearchRequest("", ldapFilter: "", searchScope: SearchScope.Base, attributeList: null);
    

    对于我的特殊情况,这是可行的,因为两个重载的第二个参数不仅在类型上而且在名称上也不同(ldapFilter 与 filter)。

不过,如果不需要任何变通方法,那就太好了。

4

1 回答 1

3

由于隐式转换,第二个重载可能仍然适用。

认为在这种情况下,string总是会选择,因为它完全匹配。但是该算法可能更通用,并且当它认为它需要知道其他重载具有的确切类型时会导致错误。

有问题的情况示例:

class A
{}

class B
{
    public static implicit operator B(A a)
    {
        return null;
    }
}

class C
{
    public static implicit operator C(A a)
    {
        return null;
    }
}

public static void M(B b)
{}

public static void M(C a)
{}

在这里,类型BC来自不同的程序集。现在,如果您调用M(new A()),将选择哪个重载可能取决于引用的程序集。由于这种行为是不可取的,为了安全起见,编译器放弃了。

就像我说的那样,您的示例并不完全像这样,但编译器很可能遵循相同的规则。

于 2012-02-16T01:48:29.467 回答