繁体   English   中英

使用params关键字时C#中的方法重载行为异常

[英]Method overloading in C# behaving unexpectedly when using params keyword

好,回到基础。 我想知道如何正确地使用params参数重载方法。

这是我的情况。 我从常规方法开始:

public void MyMethod(MyObject mo)
{
    // method body
}

我为此创建了一个重载:

public void MyMethod(MyObject mo, params string[] fields)
{
    // new method body

    MyMethod(mo);
}

明显的目的是为了MyMethod(new MyObject()); 执行原始方法和MyMethod(new MyObject(), "field0"/*, etc...*/); 执行重载方法。 但这不是我发现的情况。

实际发生的是MyMethod(new MyObject()); 执行重载方法!

我不明白 在这种情况下,我将如何执行原始方法?

用实际代码更新

好的,这是产生所描述行为的实际代码。

Class1Base.cs:

public class Class1Base
{
    public virtual void MyMethod(MyObject ob)
    {
        Console.WriteLine("Called Class1Base");
    }
}

将Class1.cs:

public class Class1 : Class1Base
{
    public override void MyMethod(MyObject ob)
    {
        Console.WriteLine("called overridden method");
    }

    public void MyMethod(MyObject ob, params string[] fields)
    {
        Console.WriteLine("called OVERLOADED method");
    }
}

MyObject.cs:

public class MyObject
{
    public int Id { get; set; }
    public string Description { get; set; }
}

然后,当我以这种方式执行此代码时:

var myClass = new Class1();
var myObject = new MyObject();
myClass.MyMethod(myObject);
myClass.MyMethod(null);
myClass.MyMethod(null, "string");

控制台显示:

called OVERLOADED method
called OVERLOADED method
called OVERLOADED method

我希望它能显示:

called overridden method
called overridden method
called OVERLOADED method

为什么不呢?

我认为您没有告诉我们整个故事。 C#5规范的第7.3.5.2节(标题为“更好的功能成员”)部分说明:

•否则,如果MP以其正常形式适用并且MQ具有params数组并且仅以其扩展形式适用,则MP比MQ更好。

这似乎是事实,因为params版本需要“扩展”为零长度数组。 实际上,在本地尝试代码会产生调用非params版本的预期结果。

更新 :响应您的编辑,答案现在很清楚:您正在从Class1调用方法,这意味着在执行重载解析时,最初不考虑标记为override方法。 并且由于非重写方法适用(尽管以扩展形式存在),因此选择了该方法。

具体而言,第7.6.5.1节部分内容如下:

•候选方法的集合减少为仅包含大多数派生类型的方法:对于集合中的每个方法CF,其中C是声明方法F的类型,将删除在C的基本类型中声明的所有方法从集合。

基类MyMethod()从候选集中排除,因此算法不会选择它。


此行为背后的确切理由是避免出现“脆性基类”问题。 假设我们具有以下类层次结构:

class A
{
}

class B : A
{
    public void MyMethod(object o) { }
}

以及以下呼叫站点:

new B().MyMethod("a string");

显然,这将解析为采用objectMyMethod() 但是现在假设A的创建者(也许在另一个团队工作)决定A应该具有MyMethod() 因此,他们改变了班级:

class A
{
    public void MyMethod(string s);
}

现在想象一下如果不从基本类型中排除方法会发生什么。 您的呼叫本来可以B.MyMethod()解析为B.MyMethod() ,但会立即解析为A.MyMethod() (因为string是更好的匹配项。)C#的设计者不想让另一个人使用完全不同的团队默默地更改代码的含义。

有关脆弱的基类问题的更多信息, Eric Lippert的(旧)博客中有许多关于该主题的文章。 只是搜索一下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM