2013-08-20 7 views
0

В приведенном ниже коде представлен вывод;создание экземпляров общих классов в C#

Эрни Bert Elmo

Почему последний выход Elmo? Разве это не Эрни? Потому что я создаю объект dog.Creature с new 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; } } 
} 
+7

Это своего рода сбивает с толку. – sircodesalot

+2

Компилятор создает предупреждение, объясняющее, что здесь происходит. Мой совет заключается в том, что вы привыкли читать вывод компилятора, когда пытаетесь понять его поведение. –

ответ

15

Во-первых, это не имеет ничего общего с дженериками. Вы получите точно такое же поведение, если вы пишете:

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

Не забывайте, что тип во время компиляции Dog.Creature является Creature.

Я думал, что свойство Name класса Cat переопределяет свойство Name класса Creature.

Нет, потому что это не виртуальная собственность, и вы не использовали override. Вы должны иметь время компиляции предупреждение явно о том, что вы скрываете член, не перекрывая его:

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

При изменении Cat и Creature быть, как это, он будет работать:

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; } } 
} 

... но лично я постараюсь избежать этого в любом случае. Почему бы просто не использовать установщик в Creature? Почему вы хотите, чтобы в объекте Cat было два поля _name? Не похоже, что они предназначены для различных целей, не так ли?

Непонятно, чего вы пытаетесь достичь, но я почти наверняка дал бы классу Creature конструктор, принимающий имя в качестве параметра. Вероятно, я бы сделал свойство read-only, если это вообще возможно.

+0

Благодарим вас за объяснения, но настоящая проблема не является переопределением или скрытием собственности. Я имею в виду, что я скомпилировал этот код без каких-либо ошибок. Поэтому код разрешен компилятором. Предположим, что я написал этот код намеренно. Мне просто интересно, как эта часть кода: Console.WriteLine (dog.Creature.Name); возвращает мне «Элмо»? Каковы предположения? – Mikail

+1

@mikail: вы скомпилировали его без * ошибок *, но код, который вы предоставили, дает * предупреждения *, и да, проблема * - это отказ от переопределения. Вы думали, что переоцениваете собственность, но вы этого не сделали. 'dog.Creature.Name' будет вызывать' Creature.Name', который не называется полиморфно (потому что он не виртуальный). –

+0

Хорошо, это понятно, но как это возможно, что кошка называет свой собственный класс, но dog.Creature называет его свойство базового класса, хотя dog.Creature создается экземпляром класса Cat? Не следует ли назвать свойство класса Cat? – Mikail

3

Я думал, что имя свойства класса Cat переопределяет имя свойства класса Creature

Нет, это скрывает это. У вас есть два разных свойства с тем же именем. Если вы хотите переопределение это, вам нужно сделать базовую свойство 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; } } 
} 

Как к почему вы видите «Элмо» вместо «Эрни» - это потому, что Dog является Animal<Creature>, поэтому собственность Dog.Creature имеет тип Creature.Даже если вы переходите в Cat, поскольку свойство Name не является переопределенным, Creature.Name. Если бы у вас было overrodeName, тогда вместо него назовем Cat.Name.

+0

Итак, вы говорите, что свойство Dog.Creature - это свойство Creature и Name класса Cat, которое скрывает свойство Name класса Creature, когда я это делаю: ** var cat = new Cat() ** .. Но как он не скрывается, когда я делаю: ** dog.Creature = new Cat() **? Разве правая сторона обоих экземпляров (новые Cat(), новый Cat()) не скрывают свойства левой стороны (var cat, dog.Creature)? Поскольку обе левые стороны - это базовые классы, а обе стороны - подклассы. – Mikail

+0

'dog.Creature' - это« Существо ». Когда вы вызываете 'dog.Creature.Name', он вызывает' Creature.Name'. Поскольку 'Name' не является полиморфным (' virtual'), он не может быть переопределен базовыми классами. Чтобы вызвать 'Cat.Name', вы должны явно его использовать:' ((Cat) dog.Creature) .Name', который не будет работать во время выполнения, если значение 'Creature' на самом деле не' Cat'. –

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. 
Смежные вопросы