鉴于
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
表现得这样?换句话说,为什么this
表示base
或this
?
对我来说,明确调用base.Speak()
会更有意义。特别是当说话不是虚拟时,令人惊讶的是,当virtual
被删除时仍然会调用Speak()。我从OO意义上理解IS-A关系,但我不能在C#中解决这个特定问题。当人们编写神级UI(几乎每个企业都这样做)时,这尤其令人讨厌。我正在寻找“this”里面的“Speak()”当我应该看“base”。
答案 0 :(得分:3)
不是那样的。如果 是dog
中的发言方法,那么它就是基本方法的 override
。如果它不存在,则调用dogInstance.Speak将在Dog的任何基类中查找Speak()方法。
答案 1 :(得分:3)
子语句自动从其基类继承行为。如果您从Dog
继承Animal
以外的任何内容,那么this.Speak()
和base.Speak()
都会引用Speak()
中实现的Animal
版本}}
如果Dog
覆盖Speak()
,则特殊事情开始发生。除非Speak()
为virtual
,否则无法执行此操作。 (virtual
关键字不控制继承,它控制覆盖。)
仅当Dog
覆盖Speak()
base.Speak()
时才会执行特殊操作:在这种情况下,调用Speak()
(或this.Speak()
)将执行{{1} }的实现,因为Dog
override
的实现。这是Animal
变得有用的地方:它允许您通过指定要执行基类的实现而不是覆盖来绕过此行为。
这种风格的常见用法是构造函数。例如:
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
答案 2 :(得分:2)
这是OO的基本要点之一。如果您不提供覆盖,则使用父方法。
此外,即使您删除了virtual
,也会调用Dog.Speak
,因为您没有以多态方式访问this
。
答案 3 :(得分:1)
this
表示this
,而不是其他任何内容。
在第一个示例中,您有Speak(..)
函数的覆盖,因此this
会调用该函数。
在第二种情况下,没有任何覆盖,所以它“爬上”派生树并选择第一个合适的函数。在您的情况下,其中一个是Speak(..)
的{{1}}。
答案 4 :(得分:0)
VB.Net只有MyClass
关键字(而不是My
关键字,相当于C#中的this
。不幸的是,C#中没有MyClass
个等效关键字。