【问题标题】:Why using "new" when hiding methods?为什么在隐藏方法时使用“新”?
【发布时间】:2010-08-11 13:06:00
【问题描述】:

为什么要隐藏方法时必须使用new关键字?

我有两个班级:

public class Parent
{
    public void Print()
    {
        Console.WriteLine("Parent");
    }
}

public class Child : Parent
{
    public void Print()
    {
        Console.WriteLine("Child");
    }
}

以下代码产生给定的输出:

Parent sut = new Child();
sut.Print();

输出:父级

Child sut = new Child();
sut.Print();

输出:孩子

我知道如果隐藏不是故意的,这可能是个问题,但是否有任何其他理由使用“新”(除了避免警告)?

编辑:

可能是我不清楚。这是相同的情况:

public void foo(Parent p)
{
 p.Print();
}

被称为:

Child c = new Child;
foo (c);c

【问题讨论】:

标签: c# .net


【解决方案1】:

不,但避免警告非常重要。隐藏引起的错误可能很隐蔽,而在 C++(它只是让你这样做)之后,Java 和 C# 都选择了两种不同的方法来防止它们。

在 Java 中,不可能隐藏基类方法。如果您尝试这样做,编译器会尖叫血腥谋杀。

在 C# 中,有“new”关键字。它允许你明确表示你想隐藏一个方法,如果你不使用它,编译器会警告你。许多开发人员将代码编译器设为不带警告的规则,因为警告可能是错误代码的标志。

毕竟,我从来不用隐藏。我会仔细考虑我什至考虑使用它的原因,因为它的行为很奇怪,而且几乎不是我想要的。

【讨论】:

  • 同意,但在一种情况下您可能需要使用 new。我在下面的答案中进行了描述。
【解决方案2】:

如果您尝试使用继承,您应该在基类中创建方法virtual,在子类中创建override

语言设计者已决定,当不使用这些关键字时,应使用 new 关键字显式完成方法隐藏。

【讨论】:

    【解决方案3】:

    隐藏是个坏主意。它使代码更加混乱,您的意图也不清楚。编程语言是关于向编译器和其他程序员表达你的意图。如果没有 new 关键字,则不清楚您的意图是覆盖还是隐藏,或者您是否只是不了解基本方法。

    还有一个万无一失的元素。 “用脚射击自己。你确定吗?确定/取消”。

    真正的问题是为什么一开始就允许隐藏。不允许隐藏的问题是,如果您从另一个程序集中的类派生并添加 Foo() 方法,然后更新其他程序集以添加 Foo() 方法,则不允许隐藏会破坏您的代码。

    【讨论】:

    • 同意,我在 Jon 的 cmets 上还有另一个答案。
    【解决方案4】:

    扩展 Jon Hanna 所说的话...

    警告的重点是告诉您存在您可能不知道的名称冲突。当您收到警告时,您应该执行以下操作之一:

    1. 添加 virtual 和 override 以多态地覆盖基类中的方法
    2. 重命名您的方法,使其名称不再与基类中的方法冲突
    3. 添加新的以明确您隐藏该方法的意图

    如果您在基类中扩展或改进方法的行为,请使用 virtual 和 override,正如其他人所说的那样。

    如果您刚刚编写了您的方法,并发现您有一个您不知道的名称冲突,并且您打算覆盖,只需重命名您的方法。 p>

    选项 1 或 2 通常更可取。那么什么时候应该使用选项 3?

    当基类不是您的代码时,您使用选项 3。您没有向其添加虚拟的选项。你需要新的典型场景是这样的:

    您购买了第三方库。它有一个有趣的类。您从该类继承并添加原始作者未提供的新方法。到目前为止,没有涉及隐藏或覆盖。现在您收到了该库的第 2 版,其中包含您想要使用的一些新功能。作者在他们的类中添加了一个新方法,它的名称与您在派生类中编写的方法发生冲突。

    如果你的方法用的不是很多,你应该重命名它,选项2。但是如果你的方法有很多依赖,重命名它会非常混乱。因此,您添加新的表示您的方法与基类中的方法之间没有没有逻辑连接,即使它们碰巧具有相同的名称。您没有能力为基类中的方法添加虚拟,也不想这样做。这两种方法是由不同的开发人员设计的,您的方法没有改进或扩展基类中的方法——当您编写自己的方法时,基类中的方法并不存在。

    因此,您很少需要 new 关键字,但是当您这样做时,它很重要。

    【讨论】:

      【解决方案5】:

      因为它明确表明您故意隐藏父方法,而不是覆盖它。当你不使用new 时会有一个警告,因为你的子类的方法可能有错字,并且不小心隐藏了父方法会导致一些细微的错误。

      【讨论】:

        【解决方案6】:

        如果基类中具有相同签名的方法未标记为abstractvirtual,则必须使用new 关键字。

        【讨论】:

        • @Lucas,没错!我忘记了那部分。
        【解决方案7】:

        只需标记Parent 的方法virtual。然后你会在你的孩子班上做public override void Print()

        public class Parent 
        { 
            public virtual void Print() 
            { 
                Console.WriteLine("Parent"); 
            } 
        } 
        
        public class Child : Parent 
        { 
            public override void Print() 
            { 
                Console.WriteLine("Child"); 
            } 
        } 
        

        这样你得到了真正的继承,你可以通过调用base.Print()从Child调用父母Print()方法

        【讨论】:

        • 很好的例子,但没有回答问题 ;)
        【解决方案8】:

        为什么要隐藏方法时必须使用new关键字?

        不是必要的。 new 这里唯一的作用就是抑制警告。

        问题可能是:为什么隐藏基类成员不是错误?

        【讨论】:

          【解决方案9】:

          对您问题的补充的答案

          可能是我不清楚。这是相同的 像这样的情况:

          public void foo(父 p) { p.打印(); } 被称为:

          孩子 c = 新孩子;富 (c);

          答案是foo(c) 将输出Parent。如果您像示例中那样调用父类,则隐藏父方法的方法将不会执行。要获得 Child 的输出,您需要使用 virtual 和 override,如前面的答案中所述。

          【讨论】:

            【解决方案10】:

            您可以在此处查看允许隐藏方法的原因及其范围的详细信息。

            https://msdn.microsoft.com/en-us/library/aa691135(v=vs.71).aspx

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-07-27
              • 2016-02-13
              • 1970-01-01
              • 2011-11-03
              • 2013-10-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多