重写接口实现时出现错误的编译器警告

本文关键字:错误 编译器 警告 接口 实现 重写 | 更新日期: 2023-09-27 18:21:18

考虑以下代码:

interface IFooable
{
    void Foo();
}
class Blah : IFooable
{
    public void Foo()
    {
        Console.WriteLine("Hi from 'Blah'");
    }
}
class Bar : Blah, IFooable
{
    public void Foo()
    {
       Console.WriteLine("Hi from 'Bar'");
    }
}

编译此代码将在编译器中发出以下警告:

"Bar.Foo()"隐藏继承的成员"Blah.Foo()"。如果要隐藏,请使用new关键字。

但"Foo"是一种接口方法实现,根据定义,IIRC是虚拟的。如果您运行以下代码:

var fooableList = new List<IFooable>();
fooableList.Add(new Blah());
fooableList.Add(new Bar());
foreach (var fooable in fooableList)
{
    fooable.Foo();
}

毫无疑问,这将像一个虚拟调用一样输出:

你好,来自Blah

你好,来自"酒吧"

这是非常误导性的,更糟糕的是,如果你继续按照编译器的警告建议,将Bar.Foo标记为new,这在程序的输出中根本没有意义。是的,我知道我正在使CCD_;两次";IFooable,但这仍然是合法代码,由此产生的警告是完全错误的。

我是不是对接口和方法隐藏的工作原理有深刻的误解,还是这是一个角落里的编译器警告故障?

重写接口实现时出现错误的编译器警告

您所做的不仅仅是"两次实现IFooable"。考虑以下类似代码:

interface IFooable
{
    void Foo();
}
class Blah : IFooable
{
    public void Foo()
    {
        Console.WriteLine("Hi from 'Blah'");
    }
}
class Bar : Blah
{
    public void Foo()
    {
       Console.WriteLine("Hi from 'Bar'");
    }
}

这里您清楚地隐藏了BlahFoo的实现。使Bar也从IFooable派生并不能改变这一事实。为了不隐藏它,您需要在Blah本身中将其标记为虚拟。

请参阅MSDN。

Blah类有一个Foo方法。酒吧班有Blah班。所以Blah类有一个Foo方法。这不应该两次实现Interface。