使用params string []和继承的重载方法时的怪癖

Cod*_*tig 4 c#

我有一个这样的课

public class Child
{
    public string ToXml()
    {
        return "Child : ToXml()";
    }

    public string ToXml( params string[] fields )
    {
        return "Child : ToXml(...)";
    }
}
Run Code Online (Sandbox Code Playgroud)

创建类Child的实例并调用ToXml()返回第一个重载的函数,该函数很好并且花花公子.

var obj = new Child();
Console.WriteLine( obj.ToXml() );
Run Code Online (Sandbox Code Playgroud)

输出:

Child : ToXml()
Run Code Online (Sandbox Code Playgroud)

但是当我添加一个Parent类并将Child类更改为:

public class Parent
{
    public virtual string ToXml()
    {
        return "Parent : ToXml()";
    }
}

public class Child : Parent
{
    public override string ToXml()
    {
        return "Child : ToXml()";
    }

    public string ToXml( params string[] fields )
    {
        return "Child : ToXml(...)";
    }
}
Run Code Online (Sandbox Code Playgroud)

输出已更改为:

Child : ToXml(...)
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么这样的行为?(我使用的是使用.NET 3.5的VS2010)

我通过将第二个重载函数更改为"修复"此问题:(我取出了params关键字

public class Child : Parent
{
    public override string ToXml()
    {
        return "Child : ToXml()";
    }

    public string ToXml( string[] fields )
    {
        return "Child : ToXml(...)";
    }
}
Run Code Online (Sandbox Code Playgroud)

这让我想到了我的第二个问题(让我知道我是否应该把它分成两个不同的帖子),这些功能之间有什么区别

ToXml( params string[] fields )
Run Code Online (Sandbox Code Playgroud)

ToXml( string[] fields )
Run Code Online (Sandbox Code Playgroud)

当我调用这样的函数时,它们似乎都工作:

var obj = new Child();
Console.WriteLine( obj.ToXml( new [] { "foo", "bar" ) );
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 7

为什么这样的行为?

目前尚不清楚"喜欢这个"是什么意思,所以首先,让我们正确地描述行为.您遇到的行为是:出于重载解析的目的,派生类型上的适用候选方法总是优于基类型上的适用候选方法.而且,虚方法被认为是声明它的类型的方法,而不是覆盖它的类型.

还不清楚"为什么"是什么意思?"为什么"这些问题很难回答; 在某种意义上,问题已经得到解答:为什么编译器会表现出这种行为?因为这是超载分辨率打破的指定规则的结果.但是你可能会说这个问题已被乞求; 现在的问题是"那么为什么规范是这样编写的呢?"

规范是这样编写的,因为这样做可以减轻脆弱的基类问题. 脆弱的基类问题是你有两个团队,一个在基类上工作,另一个在派生类上工作.如果在基类上工作的团队引入了一个新方法,那么这样做不应该改变使用派生类的代码的行为.如果是,则基类更改已"破坏"派生类行为.C#经过精心设计,可以缓解脆弱的基类问题.

即使将脆弱的基类问题排除在外,在派生类上优先考虑该方法也是有意义的.派生类的开发人员比基类的开发人员拥有更多信息.他们知道他们手里拿着香蕉; 基类的开发人员只知道他们有一个Fruit.调用应该转到开发人员编写的方法,他们尽可能提供更多信息.

然后你可能会说"好吧,这个问题再次被乞求;现在我想知道为什么减轻脆弱的基类问题很重要".而不是继续这种无限的倒退,我只会把它留在那; 如果你想了解更多,那就问一个不太模糊的问题.

如果脆弱基类故障缓解的主题让您感兴趣,请考虑阅读我冗长的系列文章.

这些功能有什么区别

不同之处在于,一个人可能是其扩展形式或正常形式的适用候选人,而另一个人只有一个适用的候选人形式.