0

在下面的代码中,输出是;

厄尼·伯特·埃尔莫

为什么最后一个输出是 Elmo?不应该是厄尼吗?因为我dog.Creaturenew Cat();. 我认为类的Name属性Cat会覆盖类的Name属性Creature

class Class1
{
    public static void Main(string[] args)
    {
        var dog = new Dog();
        var cat = new Cat();
        dog.Creature = new Cat();

        Console.WriteLine(cat.Name); //outputs Ernie
        Console.WriteLine(dog.Name); //outputs Bert 
        Console.WriteLine(dog.Creature.Name); //outputs Elmo, why not Ernie?
        Console.Read();
    }
}
public class Animal<T> where T : Creature
{
    public T Creature { get; set; }
    private string _name = "Oscar";
    public string Name { get { return _name; } set { _name = value; } }
}
public class Creature
{
    private string _name = "Elmo";
    public string Name { get { return _name; } set { _name = value; } }
}
public class Cat : Creature
{
    private string _name = "Ernie";
    public string Name { get { return _name; } set { _name = value; } }
}
public class Dog : Animal<Creature>
{
    private string _name = "Bert";
    public string Name { get { return _name; } set { _name = value; } }
}
4

3 回答 3

15

首先,这与泛型无关。如果你写,你会得到完全相同的行为:

Creature cat = new Cat();
Console.WriteLine(cat.Name);

不要忘记编译时类型Dog.CreatureCreature.

我认为 Cat 类的 Name 属性覆盖了 Creature 类的 Name 属性。

不,因为它不是虚拟财产,而且您还没有使用override. 您应该有一个编译时警告明确说明您正在隐藏该成员,而不是覆盖它:

Test.cs(30,19): warning CS0108: 'Cat.Name' hides inherited member
        'Creature.Name'. Use the new keyword if hiding was intended.

如果你改变CatCreature成为这样,它将起作用:

public class Creature
{
    private string _name = "Elmo";
    public virtual string Name { get { return _name; } set { _name = value; } }
}

public class Cat : Creature
{
    private string _name = "Ernie";
    public override string Name { get { return _name; } set { _name = value; } }
}

...但我个人还是会尽量避免这种情况。为什么不直接使用 setterCreature呢?为什么要在一个对象中有两个_name字段?Cat这不像它们是为了服务不同的目的,是吗?

目前尚不清楚您要实现什么,但我几乎可以肯定会给Creature该类一个以名称作为参数的构造函数。如果可能的话,我可能也会将该属性设为只读。

于 2013-08-20T13:41:08.667 回答
3

我认为 Cat 类的 Name 属性覆盖了 Creature 类的 Name 属性

不,它隐藏了它。您有两个具有相同名称的不同属性。如果你想覆盖它,你需要制作基础属性并在继承的类上virtual使用关键字:override

public class Creature
{
    private string _name = "Elmo";
    public virtual string Name { get { return _name; } set { _name = value; } }
}
public class Cat : Creature
{
    private string _name = "Ernie";
    public override string Name { get { return _name; } set { _name = value; } }
}

至于为什么你看到“Elmo”而不是“Ernie” - 这是因为Dog是一个Animal<Creature>,所以属性Dog.Creature是类型Creature。即使您传入 a Cat,由于该Name属性未被覆盖Creature.Name也会被调用。如果你有overrode Name, thenCat.Name会被调用。

于 2013-08-20T13:42:14.447 回答
3

一个好的做法是阅读 IDE 给您的警告。

warning CS0108: 'Program.Cat.Name' hides inherited member 'Program.Creature.Name'. Use the new keyword if hiding was intended.
warning CS0108: 'Program.Dog.Name' hides inherited member 'Program.Animal<Program.Creature>.Name'. Use the new keyword if hiding was intended.
于 2013-08-20T13:43:02.240 回答