Как скрыть унаследованное свойство в классе без изменения унаследованного класса (базового класса)?
Если у меня есть следующий пример кода:
public class ClassBase
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ClassA : ClassBase
{
public int JustNumber { get; set; }
public ClassA()
{
this.ID = 0;
this.Name = string.Empty;
this.JustNumber = string.Empty;
}
}
Что мне делать, чтобы скрыть свойство Name
(не показано как член членов ClassA) без изменения ClassBase
?
Ответы
Ответ 1
Я чувствую запах кода здесь. По моему мнению, вы должны наследовать базовый класс только в том случае, если вы реализуете все функциональные возможности этого базового класса. То, что вы делаете, на самом деле не представляет объектно-ориентированных принципов. Таким образом, если вы хотите наследовать от своей базы, вы должны внедрять имя, иначе у вас есть наследование неправильно. Ваш класс A должен быть вашим базовым классом, и ваш текущий базовый класс должен наследовать от A, если это то, что вы хотите, а не наоборот.
Однако не слишком далеко отклоняться от прямого вопроса. Если вы захотели погрязнуть в "правилах" и хотите продолжить путь, который вы выбрали, вот как вы можете это сделать:
Соглашение заключается в том, чтобы реализовать свойство, но вызывать исключение NotImplementedException при вызове этого свойства, хотя мне тоже это не нравится. Но это мое личное мнение и это не меняет того факта, что это соглашение все еще стоит.
Если вы пытаетесь устаревать свойство (и оно объявлено в базовом классе как виртуальное), вы можете либо использовать на нем атрибут Obsolete:
[Obsolete("This property has been deprecated and should no longer be used.", true)]
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
}
}
( Изменить:. Как отметил Брайан в комментариях, второй параметр атрибута вызовет ошибку компилятора, если кто-то ссылается на свойство Name, поэтому они не смогут использовать его даже хотя вы реализовали его в производном классе.)
Или, как я упоминал, используйте NotImplementedException:
public override string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
Однако, если свойство не объявлено как виртуальное, вы можете использовать новое ключевое слово для его замены:
public new string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
Вы все равно можете использовать атрибут Obsolete таким же образом, как если бы метод был переопределен, или вы можете выбросить NotImplementedException, в зависимости от того, что вы выберете. Я бы, вероятно, использовал:
[Obsolete("Don't use this", true)]
public override string Name { get; set; }
или
[Obsolete("Don't use this", true)]
public new string Name { get; set; }
В зависимости от того, был ли он объявлен как виртуальный в базовом классе.
Ответ 2
Хотя технически это свойство не будет скрыто, один из способов не рекомендовать его использовать - добавить атрибуты:
[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
Это то, что System.Windows.Forms делает для элементов управления, свойства которых не подходят. Например, свойство Text находится в Control, но оно не имеет смысла для каждого класса, наследуемого от Control. Так, например, в MonthCalendar свойство Text выглядит следующим образом (для источника онлайновой ссылки):
[Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
Bindable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
get { return base.Text; }
set { base.Text = value; }
}
- Возможность просмотра - отображается ли элемент в окне "Свойства"
- EditorBrowsable - показывает ли элемент в раскрывающемся списке Intellisense
EditorBrowsable (false) не помешает вам ввести свойство, и если вы используете свойство, ваш проект все равно будет компилироваться. Но так как свойство не отображается в Intellisense, не будет так очевидно, что вы можете использовать его.
Ответ 3
Просто скройте его
public class ClassBase
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ClassA : ClassBase
{
public int JustNumber { get; set; }
private new string Name { get { return base.Name; } set { base.Name = value; } }
public ClassA()
{
this.ID = 0;
this.Name = string.Empty;
this.JustNumber = 0;
}
}
Примечание. Имя все равно будет публичным членом ClassBase, учитывая ограничение не изменять базовый класс, нет способа остановить это.
Ответ 4
Зачем наследовать силу, когда это не нужно?
Я думаю, что правильный способ сделать это - сделать has-a вместо is-a.
public class ClassBase
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ClassA
{
private ClassBase _base;
public int ID { get { return this._base.ID; } }
public string JustNumber { get; set; }
public ClassA()
{
this._base = new ClassBase();
this._base.ID = 0;
this._base.Name = string.Empty;
this.JustNumber = string.Empty;
}
}
Ответ 5
Я не думаю, что многие из отвечающих здесь людей вообще понимают наследование. Необходимо наследовать от базового класса и скрывать его когда-то общедоступные переменные и функции. Например, допустим, у вас есть базовый двигатель, и вы хотите создать новый двигатель с наддувом. Что ж, 99% движка вы будете использовать, но вы немного доработаете его функциональность, чтобы он работал намного лучше, и все же есть некоторые функциональные возможности, которые следует показывать только внесенным изменениям, а не конечному пользователю. Потому что мы все знаем, что каждый выпускаемый MS класс не нуждается в каких-либо модификациях.
Помимо использования нового, чтобы просто переопределить функциональность, это одна из вещей, которую Microsoft в их бесконечном мудрости... ох, я имею в виду ошибки, считающиеся инструментом, больше не стоящим.
Лучший способ сделать это сейчас - многоуровневое наследование.
public class classA
{
}
public class B : A
{}
public class C : B
{}
Класс B выполняет всю вашу работу, а класс C - это то, что вам нужно.
Ответ 6
Я полностью согласен с тем, что свойства не должны удаляться из базовых классов, но иногда у производного класса может быть другой более подходящий способ ввода значений. В моем случае, например, я наследую от ItemsControl. Как мы все знаем, ItemsControl имеет свойство ItemsSource, но я хочу, чтобы мой элемент управления объединял данные из двух источников (например, Person и Location). Если бы я хотел, чтобы пользователь вводил данные с помощью ItemsSource, мне нужно было бы разделить и затем перекомпилировать значения, поэтому я создал 2 свойства для ввода данных. Но вернемся к исходному вопросу, это оставляет ItemSource, который я не хочу использовать, потому что я "заменяю" его своими собственными свойствами. Мне нравятся идеи Browsable и EditorBrowsable, но это все равно не мешает пользователю использовать его. Основной момент здесь заключается в том, что наследование должно содержать MOST свойств, но когда есть большой сложный класс (особенно те, в которых вы не можете изменить исходный код), переписывание всего будет очень неэффективным.
Ответ 7
Вы не можете, что вся точка наследования: подкласс должен предлагать все методы и свойства базового класса.
Вы можете изменить реализацию, чтобы вызвать исключение при вызове свойства (если оно было виртуальным)...
Ответ 8
Я думаю, что это плохой дизайн, если вам нужно это сделать, особенно если вы можете разработать код с нуля.
Почему?
Хороший дизайн - позволить базовому классу совместно использовать общие свойства, которые имеет определенная концепция (виртуальная или реальная). Пример: System.IO.Stream в С#.
Далее вниз по полосе плохой дизайн увеличит стоимость обслуживания и сделает реализацию сложнее и сложнее. Избегайте этого как можно больше!
Основные правила, которые я использую:
-
Минимизируйте количество свойств и методов в базовом классе. Если вы не ожидаете использовать некоторые свойства или методы в классе, который наследует базовый класс; не помещайте его в базовый класс. Если вы находитесь в стадии разработки проекта; всегда возвращайтесь к чертежной доске, чтобы затем проверить дизайн, потому что все меняется! Редизайн при необходимости. Когда ваш проект будет жить, затраты на изменение вещей позже в дизайне будут расти!
-
Если вы используете базовый класс, реализованный 3-й стороной, рассмотрите "подняться" на один уровень вместо "переопределения" с помощью "NotImplementedException" или такого. Если нет другого уровня, подумайте о разработке кода с нуля.
-
Всегда считайте, что вы закрываете классы, которые вы не хотите, чтобы кто-либо мог наследовать его. Это заставляет кодировщиков "подниматься на один уровень" в "иерархии наследования" и, таким образом, "свободные концы", такие как "NotImplementedException", можно избежать.
Ответ 9
Я знаю, что вопрос старый, но что вы можете сделать, это переопределить PostFilterProperties следующим образом:
protected override void PostFilterProperties(System.Collections.IDictionary properties)
{
properties.Remove("AccessibleDescription");
properties.Remove("AccessibleName");
properties.Remove("AccessibleRole");
properties.Remove("BackgroundImage");
properties.Remove("BackgroundImageLayout");
properties.Remove("BorderStyle");
properties.Remove("Cursor");
properties.Remove("RightToLeft");
properties.Remove("UseWaitCursor");
properties.Remove("AllowDrop");
properties.Remove("AutoValidate");
properties.Remove("ContextMenuStrip");
properties.Remove("Enabled");
properties.Remove("ImeMode");
//properties.Remove("TabIndex"); // Don't remove this one or the designer will break
properties.Remove("TabStop");
//properties.Remove("Visible");
properties.Remove("ApplicationSettings");
properties.Remove("DataBindings");
properties.Remove("Tag");
properties.Remove("GenerateMember");
properties.Remove("Locked");
//properties.Remove("Modifiers");
properties.Remove("CausesValidation");
properties.Remove("Anchor");
properties.Remove("AutoSize");
properties.Remove("AutoSizeMode");
//properties.Remove("Location");
properties.Remove("Dock");
properties.Remove("Margin");
properties.Remove("MaximumSize");
properties.Remove("MinimumSize");
properties.Remove("Padding");
//properties.Remove("Size");
properties.Remove("DockPadding");
properties.Remove("AutoScrollMargin");
properties.Remove("AutoScrollMinSize");
properties.Remove("AutoScroll");
properties.Remove("ForeColor");
//properties.Remove("BackColor");
properties.Remove("Text");
//properties.Remove("Font");
}
Ответ 10
Вы можете использовать Browsable(false)
[Browsable( false )]
public override string Name
{
get { return base.Name; }
set { base.Name= value; }
}