3

给定

public class Animal
{
    public Animal()
    {
        Console.WriteLine("Animal constructor called");
    }
    public virtual void Speak()
    {
        Console.WriteLine("animal speaks");
    }
}

public class Dog: Animal
{
    public Dog()
    {
        Console.WriteLine("Dog constructor called");
        this.Speak();
    }
    public override void Speak()
    {
        Console.WriteLine("dog speaks");
  base.Speak();
    }
}

this.Speak()来电Dog.Speak()。从狗身上移开Speak(),突然this.Speak()叫起来Animal.Speak()。为什么this会有这种行为?换句话说,为什么thisbasethis

对我来说,明确调用base.Speak()更有意义。特别是当 speak 不是虚拟的时,令人惊讶的是 Speak() 在virtual被移除时仍然被调用。我从 OO 意义上理解 IS-A 关系,但我无法解决 C# 中的这个特定问题。当人们编写上帝级的 UI(几乎每个企业都这样做)时,这会变得特别烦人。当我应该查看“base”时,我正在“this”中寻找“Speak()”。

4

5 回答 5

3

这并不是说。如果 里面一个 speak 方法dog,那么它就是一个override基本方法。如果不存在,则调用 dogInstance.Speak 将在 Dog 的任何基类中查找 Speak() 方法。

于 2012-05-30T20:27:42.403 回答
3

子类自动从其基类继承行为。Dog如果您除了Animal从那时继承之外什么都不做,this.Speak()并且base.Speak()两者都引用了Speak()Animal.

开始发生特殊事情的地方是 if Dogoverrides Speak()。这是不可能的,除非Speak()is virtual。(virtual关键字不控制继承,它控制覆盖。)

只有当Dog覆盖Speak()确实base.Speak()做一些特殊的事情时:在这种情况下,调用Speak()(or this.Speak()) 将执行Dog's 的实现,因为它override是 sAnimal的实现。这就是base有用的地方:它允许您通过指定要执行基类的实现而不是覆盖来绕过此行为。

这种风格的一个常见用途是在构造函数中。例如:

public class Animal
{
    private readonly string _name;
    public Animal() : this("Animal") { }
    protected Animal(string name) { _name = name; }
    public void Speak() { Console.WriteLine(_name + " speaks"); }
}

public class NamedAnimal : Animal
{
    public NamedAnimal(name) : base(name) { }
}

// usage:
(new Animal()).Speak();  // prints "Animal speaks"
(new NamedAnimal("Dog")).Speak();     // prints "Dog speaks"

在此示例中,NamedAnimal无法访问该_name字段,但仍然可以通过调用基类的构造函数来间接设置它。但基类的签名与基类中的签名相同,因此必须使用base.

对于非构造函数,获得原本无法访问的行为也很有用。例如,如果Animal.Speak是虚拟的,那么我们可以使用覆盖来将行为附加到它上,而不是简单地替换它:

public class NamedAnimal : Animal
{
    public NamedAnimal(name) : base(name) { }
    public override Speak()
    {
        Console.Write("The animal named ");
        base.Speak();
    }
}

// usage:
(new NamedAnimal("Dog")).Speak();  // Writes "The animal named Dog speaks"
于 2012-05-30T20:32:14.410 回答
2

这是OO的基本点之一。如果您不提供覆盖,则使用父方法。

此外,即使您删除virtual,Dog.Speak也会被调用,因为您没有进行this多态访问。

于 2012-05-30T20:28:44.167 回答
1

this手段this,仅此而已。

就在您的第一个示例中,您有一个Speak(..)函数覆盖,所以this调用它。

相反,在第二种情况下,没有任何覆盖,因此它“爬上”派生树并选择第一个合适的函数。在您的情况下,其中一个Speak(..)属于Animal.

于 2012-05-30T20:28:40.703 回答
0

VB.Net 有MyClass关键字可以做到这一点(与My关键字相反,它相当于thisC# 中的关键字)。不幸的是,C# 中没有MyClass等效的关键字。

于 2012-05-30T20:29:35.357 回答