Подтвердить что ты не робот

Как скрыть унаследованное свойство в классе без изменения унаследованного класса (базового класса)?

Если у меня есть следующий пример кода:

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?

4b9b3361

Ответ 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; }
}