Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C允许在虚拟方法上使用新方法的用例是什么?_C# - Fatal编程技术网

C# C允许在虚拟方法上使用新方法的用例是什么?

C# C允许在虚拟方法上使用新方法的用例是什么?,c#,C#,作为一名Java开发人员,有一天我无意中使用了new关键字而不是override,结果让我有点惊讶 new关键字似乎删除了继承树中该级别的方法的“虚拟性”,因此在向下转换为父类的子类实例上调用方法将不会解析为子类中的方法实现 这种行为的实际用例是什么 澄清:我理解在家长不是虚拟的情况下使用new。我更好奇的是,为什么编译器允许将new和virtual结合起来 以下示例说明了不同之处: using System; public class FooBar { public virtual

作为一名Java开发人员,有一天我无意中使用了new关键字而不是override,结果让我有点惊讶

new关键字似乎删除了继承树中该级别的方法的“虚拟性”,因此在向下转换为父类的子类实例上调用方法将不会解析为子类中的方法实现

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

澄清:我理解在家长不是虚拟的情况下使用new。我更好奇的是,为什么编译器允许将new和virtual结合起来

以下示例说明了不同之处:

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

从个人经验来看,我主要看到在原始父方法未指定为virtual,但需要重写行为的情况下使用“new”关键字。应用“new”关键字“隐藏”父方法。而且,正如您在代码示例中所观察到的,使用“new”编写的方法只有在直接使用该类型时才会执行。如果使用父类型,将调用父原始方法

为了更直接地回答您的问题,它提供了一种在父方法未标记为虚拟时重写方法的方法

编辑:顺便说一句,添加“new”关键字以隐藏不可自然重写的父方法实际上不会更改生成的IL中的任何内容。但这是一种向开发人员明确声明“嘿,您在这里隐藏了一个父方法,而不是覆盖它”的方法。

用例:

  • 现在,您使用第三方库并从class
    Fruit
    派生class
    Banana
  • Banana
    中实现一个名为
    Peel
    的方法。
    水果中没有
    果皮
  • 明天,第三方将发布该库的新版本,包括一个虚拟的
    Fruit.Peel
    方法
  • 明天重新编译代码。是否要覆盖水果.果皮?很可能不是——它可能有完全不同的含义。取而代之的是,你用香蕉皮把它隐藏起来,所有现有的代码都像现在一样工作
换句话说,这主要是为了避免版本控制问题。在Java中,即使您不想覆盖,也会覆盖
果.皮
,很可能导致难以诊断的错误。

假设

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); } } 公共类基集合 { //无效返回-似乎不关心通知 //添加项的客户端;它具有IndexOf方法 //如果需要该信息,调用方可以使用 公共虚拟空添加(T项) { //将项目添加到某个位置,但不说明位置 } 公共整数索引(T项) { //说明项目所在的位置 } } 公共类列表:BaseCollection { //这里我们有一个Int32返回,因为我们的列表是友好的 //并将告诉来电者添加项目的位置
新公共虚拟整数添加(T项)//很好的例子。这是一个非常方便的选项,但我认为它有足够的陷阱来保证编译警告。如果没有
new
,但隐藏了一个方法,则会得到编译警告。其思想是,如果显式添加修饰符,这应该是一个你真正想要的标志:)