是否可以覆盖非虚方法?

zfe*_*ran 83 c# overriding overloading

有没有办法覆盖非虚方法?或者给出类似结果的东西(除了创建一个新的方法来调用所需的方法)?

我想从Microsoft.Xna.Framework.Graphics.GraphicsDevice单元测试中覆盖一个方法.

And*_*are 104

不,您不能覆盖非虚方法.你可以做的最接近的事情是通过创建一个new具有相同名称的方法来隐藏方法,但这不建议,因为它打破了良好的设计原则.

但即使隐藏一个方法也不会给你执行时间多态调度方法调用就像真正的虚方法调用一样.考虑这个例子:

using System;

class Example
{
    static void Main()
    {
        Foo f = new Foo();
        f.M();

        Foo b = new Bar();
        b.M();
    }
}

class Foo
{
    public void M()
    {
        Console.WriteLine("Foo.M");
    }
}

class Bar : Foo
{
    public new void M()
    {
        Console.WriteLine("Bar.M");
    }
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,两次调用M方法都打印Foo.M.正如您所看到的,只要对该对象的引用具有正确的派生类型,但隐藏基本方法确实会破坏多态,这种方法确实允许您为方法创建一个新实现.

我建议您不要以这种方式隐藏基本方法.

我倾向于支持那些赞成C#默认行为的人,默认情况下这些方法是非虚拟的(而不是Java).我会更进一步说,默认情况下也应该密封类.继承很难正确设计,并且有一个未标记为虚拟的方法这一事实表明该方法的作者从未想过要覆盖该方法.

编辑:"执行时多态调度":

我的意思是在调用虚方法时在执行时发生的默认行为.比方说,在我之前的代码示例中,我确实定义了一个虚方法和一个真正的重写方法,而不是定义一个非虚方法.

如果我b.Foo在那种情况下调用,CLR将正确地确定b引用所指向的对象的类型,Bar并将M适当地调度该调用.

  • 我根本不买"作者没有打算"的论点.这就像说车轮的发明者没有预料到车轮被放在车上所以我们不能在车上使用它们.我知道轮子/方法是如何工作的,我想做一些与它略有不同的事情.我不在乎创作者是否想要我.很抱歉试图复活死线程.在我弄清楚一些非常不方便的方法解决这个问题之前我只需要吹一些蒸汽我在:) (7认同)
  • 虽然"执行时多态调度"在技术上是正确的说法,但我想这可能会超过几乎所有人的头脑! (4认同)
  • @Orion 我也不明白,但在快速谷歌之后,我很高兴看到“正确”术语的使用。 (3认同)
  • 尽管作者可能确实有意禁止方法重写,但这并非一定是正确的做法。我认为XNA团队应该已经实现了IGraphicsDevice接口,以使用户在调试和单元测试方面更具灵活性。我被迫做一些非常丑陋的事情,这应该是团队所预见的。可以在这里找到进一步的讨论:http://forums.xna.com/forums/p/30645/226222.aspx (2认同)
  • 那么当您继承一个大型代码库,并且需要为新功能添加测试,但为了测试您需要实例化一大堆机器时,该怎么办。在 Java 中,我只是扩展这些部分并覆盖存根所需的方法。在 C# 中,如果方法没有被标记为虚拟,我必须找到其他一些机制(模拟库等,甚至那样)。 (2认同)

Chr*_*isF 21

不,你不能.

您只能覆盖虚拟方法 - 请参阅此处MSDN:

在C#中,派生类可以包含与基类方法同名的方法.

  • 必须将基类方法定义为虚拟.


Vya*_*sky 11

您无法覆盖 C# 中任何类的非虚拟方法(无需破解 CLR),但您可以覆盖该类实现的接口的任何方法。考虑我们有非密封的

class GraphicsDevice: IGraphicsDevice {
    public void DoWork() {
        Console.WriteLine("GraphicsDevice.DoWork()");
    }
}

// with its interface
interface IGraphicsDevice {
    void DoWork();
}

// You can't just override DoWork in a child class,
// but if you replace usage of GraphicsDevice to IGraphicsDevice,
// then you can override this method (and, actually, the whole interface).

class MyDevice: GraphicsDevice, IGraphicsDevice {
    public new void DoWork() {
        Console.WriteLine("MyDevice.DoWork()");
        base.DoWork();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是演示

class Program {
    static void Main(string[] args) {

        IGraphicsDevice real = new GraphicsDevice();
        var myObj = new MyDevice();

        // demo that interface override works
        GraphicsDevice myCastedToBase = myObj;
        IGraphicsDevice my = myCastedToBase;

        // obvious
        Console.WriteLine("Using real GraphicsDevice:");
        real.DoWork();

        // override
        Console.WriteLine("Using overriden GraphicsDevice:");
        my.DoWork();

    }
}
Run Code Online (Sandbox Code Playgroud)


slu*_*ter 5

如果未密封基类,则可以从基类继承并编写一个隐藏基类的新方法(使用方法声明中的“ new”关键字)。否则,您不能覆盖它,因为它不是原作者意图覆盖它,因此为什么它不是虚拟的。