2009-09-24 14 views
5

作为一名Java开发人员,我当时有点意外,当我有一天意外地使用了新的关键字而不是覆盖了C#允许在虚拟方法上使用新的用例是什么?

看来关键字删除了继承树中该级别的方法的“虚拟性”,因此调用子类的实例上的方法,该子类降级到父类,将无法解析到子类中的方法实现。

这种行为的实际用例是什么?

澄清:我了解父母不是虚拟时使用新的。我更加好奇为什么编译器允许合并新的和虚拟的。

下面的例子说明了区别:

using System; 

public class FooBar 
{ 
    public virtual void AAA() 
    { 
     Console.WriteLine("FooBar:AAA"); 
    } 

    public virtual void CCC() 
    { 
     Console.WriteLine("FooBar:CCC"); 
    } 
} 

public class Bar : FooBar 
{ 
    public new void AAA() 
    { 
     Console.WriteLine("Bar:AAA"); 
    } 

    public override void CCC() 
    { 
     Console.WriteLine("Bar:CCC"); 
    } 
} 

public class TestClass 
{ 
    public static void Main() 
    { 
     FooBar a = new Bar(); 
     Bar b = new Bar(); 
     Console.WriteLine("Calling FooBar:AAA"); 
     a.AAA(); 
     Console.WriteLine("Calling FooBar:CCC"); 
     a.CCC(); 
     Console.WriteLine("Calling Bar:AAA"); 
     b.AAA(); 
     Console.WriteLine("Calling Bar:CCC"); 
     b.CCC(); 
     Console.ReadLine(); 
    } 
} 

这将产生以下的输出:

Calling FooBar:AAA 
FooBar:AAA 
Calling FooBar:CCC 
Bar:CCC 
Calling Bar:AAA 
Bar:AAA 
Calling Bar:CCC 
Bar:CCC 

回答

15

使用案例:

  • 今天,您使用的是第三方库和派生来自Fruit的课程Banana
  • 您在Banana中执行名为Peel的方法。 Fruit中没有Peel
  • 明天,第三方发布该库的新版本,其中包括一个虚拟的Fruit.Peel方法
  • 您明天重新编译您的代码。你想覆盖Fruit.Peel?很可能不会 - 它可能有完全不同的含义。相反,你隐藏它与Banana.Peel和所有现有的代码工作,因为它今天。

换句话说,它主要是为了避免版本问题。在Java中,即使您不想要,您最终也会覆盖Fruit.peel,很可能导致难以诊断的错误。

+0

很好的例子。这是一个非常方便的选择,但我认为它有足够的缺陷来保证编译警告。 – PeterR 2009-09-24 16:35:54

+0

好吧,如果你*没有'new',但你隐藏了一个方法,那么你会得到一个编译警告。这个想法是,如果你明确地*添加一个修饰符,那应该是一个标志,你的意思是:) – 2009-09-24 16:53:11

2

从个人的经验来说,我主要是看在案件中使用的“新”的关键字,其中原父方法是指定为虚拟的而不是,但期望覆盖行为。 “新”关键字的应用“隐藏”父方法。而且,正如您在代码示例中所看到的,用“new”编写的方法只会在直接使用该类型时执行。如果使用父类型,父类原始方法将被调用。

要更直接地回答您的问题 - 当父方法未标记为虚拟时,它提供了重写方法的方法。

编辑:顺便说一句,添加“新”关键字来隐藏不能自然覆盖的父方法实际上并不会改变生成的IL中的任何内容。但它的明确说明,以开发商“喂,你在这里隐藏着一个父类的方法,而不是覆盖它的手段”

0

假设....

 

public class BaseCollection<T> 
{ 
    // void return - doesn't seem to care about notifying the 
    // client where the item was added; it has an IndexOf method 
    // the caller can use if wants that information 
    public virtual void Add(T item) 
    { 
    // adds the item somewhere, doesn't say where 
    } 

    public int IndexOf(T item) 
    { 
    // tells where the item is 
    } 
} 

public class List<T> : BaseCollection<T> 
{ 
    // here we have an Int32 return because our List is friendly 
    // and will tell the caller where the item was added 
    new public virtual int Add(T item) // <-- clearly not an override 
    { 
    base.Add(item); 
    return base.IndexOf(item); 
    } 
} 

这里我使用了“新”的修改,因为列表<牛逼>参考将从BaseCollection <牛逼>隐藏Add方法。默认情况下,隐藏基本成员会从编译器生成警告(如果编译设置为警告失败,则为错误)。所以我基本上是在告诉编译器......“是的,我知道我使用void return隐藏了Add方法,它是所需的功能 - 只需要使用它。”

相关问题