Могу ли я переопределить производные типы?

Насколько я знаю, в 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, которые касаются этого вопроса?

Это невозможно на любом языке .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 если только это не был другой производный тип.

  • Почему конструкторы не могут быть унаследованы в java?
  • Почему мне приходится обращаться к членам базового classа шаблонов через этот указатель?
  • Есть ли что-то вроде annotations Inheritance в java?
  • Как определить закрытый class в C ++?
  • Entity Framework DB-First, реализовать наследование
  • Должен ли я избегать многозадачного (конкретного) наследования в Django любыми способами?
  • Переопределение статических переменных при подclassификации
  • доступ к защищенному члену базового classа в другом подclassе
  • C ++ Доступный элемент classа из указателя базового classа
  • Может ли интерфейс расширять несколько интерфейсов в Java?
  • Возвращаемый тип виртуальной функции C ++
  • Interesting Posts

    PriorityQueue.toString неверный порядок элементов

    Как исправить кодировку символа файла?

    Использование модуля Underscore с Node.js

    jQuery $ .ajax (), $ .post отправляет «ОПЦИИ» как REQUEST_METHOD в Firefox

    Сенсорные жесты в IE не работают без запуска explorer.exe

    Как подключить портативный монитор USB Type-C к графической карте с портом дисплея или hdmi

    Определить строку кода, которая вызывает ошибку сегментации?

    В каком окружении Конда работает Jupyter?

    Как я могу вставить изображение с iTextSharp в существующий PDF-файл?

    Отключить значок док-станции

    множественная компоновка для разных страниц в угловом 2

    Как преобразовать изображение растрового изображения низкого качества в вектор?

    Как отформатировать / восстановить USB-накопитель с защитой от записи с ошибками ввода-вывода?

    Разрешенные версии для приложения (22.0.0) и тестового приложения (21.0.3) отличаются

    Блок ThreadPoolExecutor, когда очередь заполнена?

    Давайте будем гением компьютера.