关于C#中方法重叠的新关键字的讨论

时间:2017-05-07 11:19:46

标签: c#

我在C#中阅读了一些关于方法重叠的“new”关键字的材料。但是我仍然没有看到“new”关键字的重要目的,除了修复警告“ CS0108 C#隐藏继承的成员。在Visual Studio中使用新关键字,如果隐藏了。”。 样本:

class ClassA
{
    public void printInfo()
    {
        Console.WriteLine("I'm A");
    }
}

测试案例1

class ClassB : ClassA
{
    public void printInfo()
    {
        Console.WriteLine("I'm B");
    }
}
class Program
{
    static void Main(string[] args)
    {
        ClassA a = new ClassA();
        a.printInfo();
        ClassB b = new ClassB();
        b.printInfo();
        ClassA ab = new ClassB();
        ab.printInfo();
        Console.ReadKey();
     }
}

测试案例2 ,带有“new”关键字:

class ClassB : ClassA
{
    public new void printInfo()
    {
        Console.WriteLine("I'm B");
    }
}
class Program
{
    static void Main(string[] args)
    {
        ClassA a = new ClassA();
        a.printInfo();
        ClassB b = new ClassB();
        b.printInfo();
        ClassA ab = new ClassB();
        ab.printInfo();
        Console.ReadKey();
     }
}

它们都具有相同的输出:

I'm A
I'm B
I'm A

不同之处在于“new”关键字修复了警告。

有人可以在这里向我展示更多关于“new”关键字有用的示例吗?

3 个答案:

答案 0 :(得分:0)

MSDN上有一篇关于何时使用Override和New关键字的好文章 Knowing When to Use Override and New Keywords

主要的想法是,当你编写public new void function()时,你告诉编译器你知道这个方法被baseclass的方法隐藏了,警告就消失了。现在,您将能够从派生类的实例和基类的实例中使用此方法,或者将其装箱到基类。

答案 1 :(得分:0)

两个代码之间没有区别。编译器只是警告你,你可能没有意识到你正在隐藏 A.printInfo并且它只是引起你的注意。

在大型代码库中,你甚至可能不拥有A,在派生类中编写一个与基类中现有方法具有相同签名的方法很容易。< / p>

使用关键字new,您可以获得三个直接优势:

  1. 您告知编译器您知道这一事实并且您故意隐藏方法/属性。
  2. 您正在向将来隐藏方法/属性的任何人审核或保留您的代码清楚明了。
  3. 如果将警告设置为编译时错误,那么您的代码实际上是编译的,这是可取的,在任何体面的质量编码环境中都是如此。

答案 2 :(得分:0)

您的代码示例都给出了相同的结果,因为添加the new modifier 并不会更改编译器的输出 - 它只是摆脱了编译器警告{{ 3}}。如果没有new,编译器会为您添加它:

  

此警告通知您应使用new; 声明变量,就好像声明中使用了新的

也就是说,由于CS0108,隐藏new并覆盖会产生相同的效果。

考虑以下情况(polymorphism):

主要课程:

public class Program
{
    public static void Main()
    {
        Developer developer = new Developer();
        PrintSalaryWithHiding(developer);
        PrintSalaryWithOverriding(developer);
    }

    public static void PrintSalaryWithHiding(Employee employee)
    {
        Console.WriteLine("Salary (with hiding): " + employee.SalaryWithHiding);
    }

    public static void PrintSalaryWithOverriding(Employee employee)
    {
        Console.WriteLine("Salary (with overriding): " + employee.SalaryWithOverriding);
    }
}

基类(请注意SalaryWithHiding不是虚拟的,SalaryWithOverriding是):

public abstract class Employee
{
    public int SalaryWithHiding
    {
        get
        {
            return 10000;
        }
    }

    public virtual int SalaryWithOverriding
    {
        get
        {
            return 10000;
        }
    }
}

派生类(注意new之前的SalaryWithHidingoverride之前的SalaryWithOverriding

public class Developer : Employee
{
    public new int SalaryWithHiding
    {
        get
        {
            return 50000;
        }
    }

    public override int SalaryWithOverriding
    {
        get
        {
            return 50000;
        }
    }
}

结果是

Salary (with hiding): 10000
Salary (with overriding): 50000

为什么?

这是因为new关键字告诉编译器,如果您有一个Developer的实例,声明Developer,则调用SalaryWithHiding方法将调用Developer类中的一个而不是Employee类中的一个(即隐藏类)。

当您拥有Developer的实例,宣布Employee时,调用SalaryWithHiding方法会调用Employee中的方法类。

您可以在以下缩减示例(try it online)中看到这一点:

主要课程:

public class Program
{
    public static void Main()
    {
        Developer developer = new Developer();
        Console.WriteLine("Developer salary when declared as developer: " + developer.SalaryWithHiding);

        // these are the same object!
        Employee employee = developer;      
        Console.WriteLine("Developer salary when declared as employee: " + employee.SalaryWithHiding);
    }
}

员工:

public abstract class Employee
{
    public int SalaryWithHiding
    {
        get
        {
            return 10000;
        }
    }
}

开发:

public class Developer : Employee
{
    public new int SalaryWithHiding
    {
        get
        {
            return 50000;
        }
    }
}

结果是:

Developer salary when declared as developer: 50000
Developer salary when declared as employee: 10000

摘要

一般来说,我会说你应该只使用new修饰符,如果你知道你在做什么,因为它打破了多态性:正如你在你自己的例子中看到的那样,当你有

ClassA ab = new ClassB();
ab.printInfo();

它在ClassA中调用了方法,好像您没有在ClassB中声明一个具有不同结果的单独方法。这可能是非常令人困惑。在基础virtual中创建方法并在派生类中重写它会更好,除非您出于某种原因需要该行为。在我的(人为的)示例中,使用new隐藏方法会导致薪水不正确!