什么是“public new virtual void Method()”是什么意思?

时间:2012-05-02 14:33:51

标签: c#

何时使用新的虚拟关键词来装饰方法?感情是什么?就像定义一个接口一样,并添加一个类来继承接口。但是使用新的虚拟来实现接口方法。

 interface IPrinter
{
    void Print();
}

 public class PrinterOne : IPrinter
{
    public void Print() 
    {
        Console.WriteLine("PrinterOne.");
    }
}

public class PrinterTwo : PrinterOne
{
    public new virtual void Print()
    {
        Console.WriteLine("PrinterTwo.");
    }
}

public class PrinterThree : PrinterTwo
{
    public override void Print()
    {
        Console.WriteLine("PrinterThree.");
    }
}

public class PrinterFour : PrinterThree
{
    public override void Print()
    {
        Console.WriteLine("PrinterFour.");
    }
}

 static void Main(string[] args)
    {
        IPrinter iprinter = new PrinterFour();
        iprinter.Print();//the output is PrinterOne? why???
        Console.ReadLine();
    }

4 个答案:

答案 0 :(得分:11)

newvirtual是两个(大多数)无关的关键字。

new表示它会影响基本方法 virtual允许子类覆盖它。

通过接口调用方法会导致调用基本方法,因为基本方法不是virtual,并且派生类没有显式重新实现接口(这将导致重新生成方法) -mapped)

答案 1 :(得分:10)

像这样使用的new关键字隐藏了成员。

我从未见过它与virtual关键字一起使用,请注意。它只是允许从PrinterTwooverride Print方法实现派生的类型。

以这种方式使用的new关键字允许类型隐藏基类型的成员,但前提是您使用的是类型本身的变量。

例如,如果你这样做:

PrinterOne one = new PrinterTwo();
one.Print();

调用PrinterTwo中的方法,因为它不是继承链的一部分。

至于你何时会这样做...当你真的,真的需要一些奇怪的原因,我想不到(反射可能?),你不能编辑PrinterOne中的代码。 / p>

就个人而言,我不会这样做。

至于输出为打印机的原因...调用IPrinter.Print会调用它所定义的类型(在这种情况下为PrinterOne),这会让你回到我上面的例子中new关键字被忽略,除非您与具有该功能的类型进行对话。

基本上,使用IPrinter类似于在上面的小例子中使用PrinterOne

要解决此问题,请使用PrinterOne方法virtual并完全删除new virtualPrinterTwo的使用。

答案 2 :(得分:4)

新修饰符

http://msdn.microsoft.com/en-us/library/435f1dw2.aspx

  

当用作修饰符时,new关键字显式隐藏从基类继承的成员。

这意味着该方法不会覆盖虚拟基类方法,但在派生类的实例上调用时仍然优先。换句话说,new方法只影响派生类的变量,而不影响基类。

虚拟修饰符

http://msdn.microsoft.com/en-us/library/9fkccyh4.aspx

  

virtual关键字用于修改方法,属性,索引器或事件声明,并允许在派生类中重写它。

这意味着可以在派生类中覆盖该方法。当您在基类变量上调用虚方法时,该变量包含已覆盖虚方法的派生类的实例,则调用派生类实现。这与新关键字的行为相反。

答案 3 :(得分:1)

这称为方法隐藏。当您需要为无法覆盖的方法提供自己的实现时,可以使用此方法。由于PrinterOne.Print不是虚方法,因此无法覆盖它。相反,new关键字用于创建隐藏原始方法的相同方法签名。将使用新方法。向此添加virtual关键字,可以通过派生类来覆盖新方法。

只有通过定义容器(例如PrintTwo)调用它时,才会调用隐藏原始方法的新方法。通过接口调用它调用原始方法。请注意,该方法从未被删除或替换,因此通过直接访问界面仍然存在原始实现。