2016-02-21 2 views
4

упрощенный пример того, что я пытаюсь достичь, выглядит так:Override унаследованное свойство с более производный тип

public class Animal 
{ 
    public virtual Teeth teeth {get;set;} 
} 

public class Mouse : Animal 
{ 
    public override SmallTeeth teeth {get; set;} // SmallTeeth Inherits from Teeth 
} 

Это, очевидно, не работает, как зубы должны быть того же типа, как и в животном класс, который будет переопределен в классе Mouse. Но может ли быть что-то подобное достигнуто, когда мне будет разрешено использовать более производный тип в любых функциях, которые унаследованы от Animal? Например, если класс Animal содержит функцию укусить:

public void Bite() 
{ 
    teeth.bite() 
    Console.WriteLine("Ouch") 
} 

Я мог бы вызвать функцию Bite() унаследованной от животных, и было бы использовать поле класса Mouse типа SmallTeeth. Это возможно? и это лучший способ сделать то, что я пытаюсь сделать? Если нет, то какой будет правильный подход к этой проблеме?

+0

@ gyttt1: Если я правильно помню, это как-то связано с концепциями ковариации. Вы можете переопределить обычный способ с помощью Teeth, и ваша реализация может вернуть объект типа SmallTeeth – pkamathk

ответ

10

Функция, которую вы хотите, называется Возвращаемый тип ковариации, а C# не поддерживает ее. (C++ делает, кстати.)

Обычный случай сделал для ковариантных типов возвращаемых:

abstract class Animal 
{ 
    public abstract Cage GetCage(); 
} 
public class Fish : Animal 
{ 
    public override Aquarium GetCage() { ... } 
} 

Это не законно, но если бы это было законным было бы безопасной. То есть, если у вас есть Животное в руке, и вы просите клетку, вы получите ее, даже если это рыба. Зачем? Потому что аквариум - это своего рода клетка.

Что вы предлагаете, хотя это не только незаконно, это небезопасно:

Animal animal = new Mouse(); 
animal.Teeth = new TRexTeeth(); 

контракта является то, что сеттер может быть вызван с любым типом зуба. Сделав производный класс более строгим в том, что он может принять, вы нарушите контракт базового класса.

Так что не делайте этого.

Есть несколько путей, хотя вы можете достичь того, чего хотите в C#.

Вот только один из них:

interface IAnimal 
{ 
    Teeth Teeth { get; } // READ ONLY 
} 

class Mouse : IAnimal 
{ 
    private SmallTeeth smallTeeth; 
    public SmallTeeth Teeth 
    { 
     get { return smallTeeth; } 
    } 

    Teeth IAnimal.Teeth { get { return this.Teeth; } } 
} 

Теперь, если вы разыгрываете мышь IAnimal вы получите свойство, которое возвращает зубы, и если вы используете мышь, как правило, вы получите свойство, которое возвращает SmallTeeth.

я опишу еще один способ решить эту проблему здесь:

Does C# support return type covariance?

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

Проведите поиск по «ковариации типа возврата в C#» для получения дополнительной информации об этом шаблоне.

3

На самом деле да.Вы могло но не должна использовать generics для этой цели, включая тип ограничение (см комментарии ниже и the post of Eric Lippert, который подробно объясняет, что вы желающие или пытаетесь достичь в вашей ситуации):

public class Animal<T> where T : Teeth 
{ 
    public virtual T teeth {get;set;} 
} 

public class Mouse : Animal<SmallTeeth> 
{ 
    public override SmallTeeth teeth {get; set;} // SmallTeeth Inherits from Teeth 
} 
+2

Это интересно, но я полагаю, что введение дженериков здесь создаст сложности/проблемы в другом месте. –

+3

Хорошее решение, но следует упомянуть и о недостатке: у животных больше нет общего супертипа (кроме «объекта»). Например, вы не можете просто создать «Список ». – Heinzi

+1

yes @Heinzi, это хороший ответ, но, к сожалению, этот недостаток является нарушителем сделки! –

Смежные вопросы