У меня есть абстрактный базовый класс, и я хочу объявить поле или свойство, которое будет иметь разные значения в каждом классе, который наследуется от этого родительского класса.
Я хочу определить его в базовом классе, чтобы я мог ссылаться на него в методе базового класса - например, переопределив ToString, чтобы сказать «Этот объект имеет свойство / поле типа ». У меня есть три способа сделать это, но мне было интересно - как лучше всего это сделать? Вопрос новичка, извините.
Вариант 1:
использовать абстрактное свойство и переопределить его в унаследованных классах. Это полезно от принудительного применения (вы должны переопределить его), и оно чисто. Но кажется немного неправильным возвращать значение жесткого кода, а не инкапсулировать поле, и это всего лишь несколько строк кода, а не просто. Я также должен объявить тело для «set», но это менее важно (и, вероятно, есть способ избежать того, о чем я не знаю).
abstract class Father
{
abstract public int MyInt { get; set;}
}
class Son : Father
{
public override int MyInt
{
get { return 1; }
set { }
}
}
Вариант 2
Я могу объявить открытое поле (или защищенное поле) и явно переопределить его в унаследованном классе. Приведенный ниже пример предупредит меня об использовании «new», и я, вероятно, могу это сделать, но он кажется неправильным и нарушает полиморфизм, что и было всем. Не похоже на хорошую идею ...
abstract class Mother
{
public int MyInt = 0;
}
class Daughter : Mother
{
public int MyInt = 1;
}
Вариант 3
Я могу использовать защищенное поле и установить значение в конструкторе. Это выглядит довольно аккуратно, но я полагаюсь на то, что конструктор всегда устанавливает это, а при наличии нескольких перегруженных конструкторов всегда есть вероятность, что путь кода не установит значение.
abstract class Aunt
{
protected int MyInt;
}
class Niece : Aunt
{
public Niece()
{
MyInt = 1;
}
}
Это немного теоретический вопрос, и я думаю, что ответ должен быть вариант 1, поскольку это единственный безопасный вариант, но я только начинаю разбираться с C # и хотел спросить это у людей с большим опытом.
источник
Ответы:
Из трех решений только вариант 1 является полиморфным .
Поля сами по себе не могут быть переопределены. Именно поэтому Вариант 2 возвращает новый предупреждение ключевом слове.
Решение для предупреждения заключается не в добавлении ключевого слова «new», а в реализации варианта 1.
Если вам нужно, чтобы ваше поле было полиморфным, вам нужно обернуть его в свойстве.
Вариант 3 в порядке, если вам не нужно полиморфное поведение. Однако следует помнить, что при доступе к свойству MyInt производный класс не контролирует возвращаемое значение. Базовый класс сам по себе способен возвращать это значение.
Вот как может выглядеть по-настоящему полиморфная реализация вашего свойства, позволяющая управлять производными классами .
источник
Вариант 2 не является начальным - вы не можете переопределить поля, вы можете только скрыть их.
Лично я бы выбрал вариант 1 каждый раз. Я стараюсь всегда держать поля закрытыми. Это, если вам действительно нужно иметь возможность переопределить свойство вообще, конечно. Другой вариант - иметь свойство только для чтения в базовом классе, которое устанавливается из параметра конструктора:
Вероятно, это наиболее подходящий подход, если значение не меняется в течение срока действия экземпляра.
источник
Вариант 2 плохая идея. Это приведет к тому, что называется затенением; По сути, у вас есть два разных члена «MyInt», один в матери, а другой в дочери. Проблема в том, что методы, которые реализованы в матери, будут ссылаться на «MyInt» матери, в то время как методы, реализованные в дочери, будут ссылаться на «MyInt» дочери. это может привести к серьезным проблемам с читабельностью и путанице в дальнейшем.
Лично я думаю, что лучший вариант - 3; потому что он обеспечивает четкое централизованное значение, и на него могут ссылаться дети, не стесняясь определять свои собственные поля - что является проблемой с вариантом 1.
источник
Вы могли бы сделать это
Виртуальный позволяет получить свойство - тело, которое что-то делает, и все же позволяет подклассам переопределять его.
источник
Вы можете определить что-то вроде этого:
Устанавливая значение только для чтения, оно гарантирует, что значение для этого класса останется неизменным в течение всего времени существования объекта.
Полагаю, следующий вопрос: зачем тебе это?
источник
Если вы создаете класс и хотите, чтобы для свойства существовало базовое значение, используйте
virtual
ключевое слово в базовом классе. Это позволяет вам при необходимости переопределить свойство.Используя ваш пример выше:
В программе:
источник
Я бы выбрал вариант 3, но у меня есть абстрактный метод setMyInt, который подклассы вынуждены реализовывать. Таким образом, у вас не будет проблемы с производным классом, забывшим установить его в конструкторе.
Кстати, с первым вариантом, если вы не указали set; в вашем абстрактном свойстве базового класса производный класс не должен будет его реализовывать.
источник
Вы можете перейти с опцией 3, если вы измените свой абстрактный базовый класс, чтобы требовать значение свойства в конструкторе, вы не пропустите ни одного пути. Я бы действительно рассмотрел этот вариант.
Конечно, тогда у вас все еще есть возможность сделать поле частным, а затем, в зависимости от необходимости, открыть защищенный или получатель публичной собственности.
источник
Я сделал это...
Таким образом, вы все еще можете использовать поля.
источник
Пример реализации, когда вы хотите иметь абстрактный класс с реализацией. Подклассы должны:
В этом случае свойства, необходимые для реализации, не должны быть доступны для использования, за исключением абстрактного класса и его собственного подкласса.
источник