【问题标题】:Shadowing in c# - base method gets called instead of derivedc# 中的阴影 - 调用基方法而不是派生方法
【发布时间】:2015-06-22 08:47:00
【问题描述】:

我试图弄清楚 c# 中阴影的概念。这是我的代码,它的行为与我预期的不同:

public class Animal
{
    public virtual void Foo()
    {
        Console.WriteLine("Foo Animal");
    }
}

public class Dog : Animal
{
    public new void Foo()
    {
        Console.WriteLine("Foo Dog");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dog dog1 = new Dog();
        ((Animal)dog1).Foo();
        Animal dog2 = new Dog();
        dog2.Foo();
    }
}

Main 中的代码被执行时,基类(Animal) 中的Foo() 被调用,从我读到的关于阴影的内容中,应该调用Dog 中的Foo()。有人可以解释我缺少什么吗?

我的例子是这样的: https://msdn.microsoft.com/en-us/library/ms173153.aspx

更新: 这是来自 msdn 的示例:

class Program
{
    static void Main(string[] args)
    {
        BaseClass bc = new BaseClass();
        DerivedClass dc = new DerivedClass();
        BaseClass bcdc = new DerivedClass();

        // The following two calls do what you would expect. They call
        // the methods that are defined in BaseClass.
        bc.Method1();
        bc.Method2();
        // Output:
        // Base - Method1
        // Base - Method2


        // The following two calls do what you would expect. They call
        // the methods that are defined in DerivedClass.
        dc.Method1();
        dc.Method2();
        // Output:
        // Derived - Method1
        // Derived - Method2


        // The following two calls produce different results, depending 
        // on whether override (Method1) or new (Method2) is used.
        bcdc.Method1();
        bcdc.Method2();
        // Output:
        // Derived - Method1
        // Base - Method2
    }
}

class BaseClass
{
    public virtual void Method1()
    {
        Console.WriteLine("Base - Method1");
    }

    public virtual void Method2()
    {
        Console.WriteLine("Base - Method2");
    }
}

class DerivedClass : BaseClass
{
    public override void Method1()
    {
        Console.WriteLine("Derived - Method1");
    }

    public new void Method2()
    {
        Console.WriteLine("Derived - Method2");
    }
}

当执行bcdc.Method1() 时,派生类中的Method1() 会被调用,而在我的示例中并非如此。

【问题讨论】:

  • 哪一点让您期望来自DogFoo() 方法会被调用?在这两种情况下,您都是通过编译时类型为 Animal 的表达式调用它。
  • C#: new versus override的可能重复
  • Car/ConvertibleCar/Minivan 准确显示了您正在尝试执行的操作。同一页。
  • 重点是,如果你想让一个方法调用转到一个被覆盖的方法,你需要一个不间断的virtual/override链。 new 中断了这条链。
  • 这表明在大多数情况下,阴影/隐藏是邪恶化身的产物,本不应该出现:请参阅stackoverflow.com/questions/2663274/… 了解可以使用它的情况(以弥补另一个缺点)语言)

标签: c# oop shadowing


【解决方案1】:

((Animal)dog1).Foo() 行中,首先将对象dog1 从Dog 转换为Animal 类型。所以它调用基类Animal中的方法。

如果你在 dog 类的 Foo 方法中使用 override 而不是 new 关键字,你会得到你预期的结果(即, Dog 类的 Foo 方法将被调用)。

在您的代码Animal dog2 = new Dog(); 中,dog2 将被创建为Animal 的对象,而不是Dog。因此,调用Foo 方法将调用Animal 类中的方法。

您可以使用以下代码((Dog)dog2).Foo(); 调用Dog 类中的Foo 方法。这里可以从Animal 转换为Dog 类,因为变量dog2 最初是从Dog 类的构造函数

创建的

【讨论】:

    【解决方案2】:

    在您的情况下,dog1Dog 通常会给您“Foo Dog”,但是因为您明确告诉它是 Animal,它会显示“Foo Animal”。有道理。

    然后,使用dog2,即Animal,您期望“Foo 动物”会触发,因为您说“嘿,你是动物”,即使您打开了virtual Animal(建议派生类应该重写这个方法,然后根据类型在运行时解析调用的内容),您使用隐藏它的new


    仍然完全可以。在他们的示例中,bcdc 的类型为 BaseClass,但在运行时,因为它是一个 Derived,并且 Method1 使用 virtual AND override,在基础和派生上,它被调用。

    因为它的method2 没有覆盖虚拟,它调用它知道的唯一一个,Base。如果不是将其定义为BaseClass,而是将其定义为DerivedClass,它会发现它是method2

    【讨论】:

      【解决方案3】:

      在您的示例中,当您执行 ((Animal)dog1).Foo()dog2.Foo() 时,会执行 Animal 的 Foo 方法,因为当您运行应用程序时,CLR 首先在 base 中搜索实现(因为对 Animal 的引用),然后检查它是否被覆盖是否在派生类型中,因为您没有覆盖基类实现,它在这两种情况下都调用基方法(Animal's Foo)而不是派生(Dog's Foo)。

      更新:

      override 和 new 关键字之间的区别非常小。 当您进行覆盖时,无论您使用哪个引用,当对象是派生类型时,它总是调用覆盖的方法。 如果你没有覆盖新关键字,你实际上是在隐藏基类实现 我的意思是你隐藏了派生类型的基类的实现而不是基类,所以当你使用派生对象的基类引用时,例如
      Base obj = new Derived(); 它总是调用基方法,因为它在派生中找不到被覆盖的方法。

      【讨论】:

      • 它正在执行派生类方法,因为您已经覆盖了 Method1。
      • 我也更新了我的答案,希望这能回答你的问题.. :)
      猜你喜欢
      • 2018-11-11
      • 2013-02-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2012-05-31
      • 1970-01-01
      • 2016-01-01
      • 1970-01-01
      相关资源
      最近更新 更多