Могу ли я переопределить производные типы?
Насколько я знаю, в C # 2.0 невозможно сделать следующее:
public class Father { public virtual Father SomePropertyName { get { return this; } } } public class Child : Father { public override Child SomePropertyName { get { return this; } } }
Я обход проблемы, создав свойство в производном classе как «новое», но, конечно, это не полиморфно.
public new Child SomePropertyName
Есть ли решение в 2.0? Как насчет каких-либо функций в 3.5, которые касаются этого вопроса?
- Интерфейсы наследуются от classа Object в java
- В чем основное отличие между наследованием и polymorphismом?
- В Java, как мне вызвать метод базового classа из переопределяющего метода в производном classе?
- Наследование в Java - создание объекта подclassа вызывает также конструктор суперclassа. Почему именно?
- Почему мы не можем сделать List mylist = ArrayList ();
- Наследование структуры в C ++
- Наследование конструкторов
- Наследование конструктора Java
- Преобразовать список в список
- Цепочка метода + наследование плохо сочетается?
- Зачем использовать интерфейсы, множественное наследование и интерфейсы, преимущества интерфейсов?
- Есть ли способ переопределить переменные classа в Java?
- Почему вы не должны расширять JFrame и другие компоненты?
Это невозможно на любом языке .NET из-за проблем с безопасностью. В языках с типом безопасности вы должны предоставить ковариацию для возвращаемых значений и контравариантность для параметров. Возьмите этот код:
class B { S Get(); Set(S); } class D : B { T Get(); Set(T); }
Для методов Get
ковариация означает, что T
должен быть либо S
либо типом, производным от S
В противном случае, если бы у вас была ссылка на объект типа D
хранящийся в переменной B
, когда вы вызывали B.Get()
вы не получили бы объект, представляемый как S
нарушает систему типов.
Для методов Set
контравариантность означает, что T
должно быть S
или типом, из которого S
вытекает. В противном случае, если бы у вас была ссылка на объект типа D
хранящийся в переменной B
, когда вы вызывали B.Set(X)
, где X
был типа S
но не типа T
, D::Set(T)
получить объект типа, которого он не ожидал.
В C # было сознательное решение запретить изменение типа при перегрузке свойств, даже если у них есть только одна из пары getter / setter, потому что в противном случае было бы очень непоследовательное поведение ( «Вы имеете в виду, я могу изменить тип на один с геттером, но не один с геттером и сеттером? Почему бы и нет?!? “ – анонимный альтернативный юниверс Newbie).
Вы можете повторно объявить (новое), но вы не можете повторно объявлять и переопределять в одно и то же время (с тем же именем). Один из вариантов – использовать защищенный метод, чтобы скрыть детали – это позволяет одновременно polymorphism и сокрытие:
public class Father { public Father SomePropertyName { get { return SomePropertyImpl(); } } protected virtual Father SomePropertyImpl() { // base-class version } } public class Child : Father { public new Child SomePropertyName { get { // since we know our local SomePropertyImpl actually returns a Child return (Child)SomePropertyImpl(); } } protected override Father SomePropertyImpl() { // do something different, might return a Child // but typed as Father for the return } }
Нет, но вы можете использовать дженерики в 2 и выше:
public class MyClass where T: Person { public virtual T SomePropertyName { get { return ...; } } }
Тогда отец и ребенок являются родовыми версиями того же classа
Из Википедии :
На языке программирования C # поддержка как ковариации возвращаемого типа, так и параметрической контравариантности для делегатов была добавлена в версии 2.0 языка. Ковариантность и контравариантность не поддерживаются для переопределения метода.
Однако он ничего не говорит о ковариации свойств.
Вы можете создать общий интерфейс для отца и ребенка и вернуть тип этого интерфейса.
Нет. C # не поддерживает эту идею (она называется «ковариация возвращаемого типа»). Однако вы можете это сделать:
public class FatherProp { } public class ChildProp: FatherProp { } public class Father { public virtual FatherProp SomePropertyName { get { return new FatherProp(); } } } public class Child : Father { public override FatherProp SomePropertyName { get { // override to return a derived type instead return new ChildProp(); } } }
т.е. использовать контракт, определенный базовым classом, но возвращать производный тип. Я сделал более подробный пример, чтобы сделать этот пункт более ясным – возrotation «этого» снова ничего не изменит.
Возможно (но беспорядочно) протестировать возвращенный объект для его фактического типа (т. Е. «Если someObject – это ChildProp»), но лучше называть его виртуальным методом, который делает правильную вещь для своего типа.
Виртуальный метод базового classа (в данном случае, виртуальное свойство) имеет не только реализацию, но и определяет контракт: дочерний class может предоставить другую реализацию SomePropertyName, если он соответствует этому контракту (например, SomePropertyName возвращает объект типа ” FatherProp “). Возврат объекта типа «ChildProp», полученного из «FatherProp», соответствует этому контракту. Но вы не можете изменить контракт в «Ребенке» – этот договор применяется ко всем classам, происходящим от «Отца».
Если вы сделаете шаг назад и посмотрите на свой более широкий дизайн, в наборе инструментов C # есть другие языковые конструкции, о которых вы также можете подумать – Generics или интерфейсы.
Нет. C # не поддерживает эту идею (она называется «ковариация возвращаемого типа»).
Из Википедии:
На языке программирования C # поддержка как ковариации возвращаемого типа, так и параметрической контравариантности для делегатов была добавлена в версии 2.0 языка. Ковариантность и контравариантность не поддерживаются для переопределения метода.
Вы можете повторно объявить (новое), но вы не можете повторно объявлять и переопределять в одно и то же время (с тем же именем). Один из вариантов – использовать защищенный метод, чтобы скрыть детали – это позволяет одновременно polymorphism и сокрытие:
Лучшими решениями были бы использование дженериков:
public class MyClass where T: Person { public virtual T SomePropertyNameA { get { return ...; } } }//Then the Father and Child are generic versions of the same class
Это самое близкое, что я мог прийти (пока):
public sealed class JustFather : Father {} public class Father where T : Father { public virtual T SomePropertyName { get { return (T) this; } } } public class Child : Father { public override Child SomePropertyName { get { return this; } } }
Без classа JustFather
вы не могли бы создать экземпляр Father
если только это не был другой производный тип.