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

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

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 ?

9 ответов


Я чувствую запах кода здесь. Я считаю, что вы должны наследовать только базовый класс, если вы реализуете все функциональные возможности этого базового класса. То, что вы делаете, на самом деле не представляет объектно-ориентированных принципов должным образом. Таким образом, если вы хотите наследовать от своей базы, вы должны реализовать имя, иначе вы получили свое наследство неправильно. Ваш класс должен быть ваш базовый класс и текущий базовый класс должен наследовать от Если вы хочу, а не наоборот.

, не отходить слишком далеко от прямого вопроса. Если ты ... --10-->сделал хотите пренебречь "правилами" и хотите продолжить путь, который вы выбрали-вот как вы можете это сделать:

соглашение заключается в реализации свойства, но бросает NotImplementedException, когда это свойство вызывается - хотя мне это тоже не нравится. Но это мое личное мнение, и это не меняет того факта, что это конвенция все еще в силе.

если вы пытаетесь устаревшее свойство (и оно объявлено в базовом классе как виртуальное), то вы можете либо использовать устаревший атрибут на нем:

[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;
    }
}

(Edit: как указал Брайан в комментариях, второй параметр атрибута вызовет ошибку компилятора, если кто-то ссылается на свойство Name, поэтому они не смогут использовать его, даже если вы реализовали его в производном классе.)

или как Я упомянул использование NotImplementedException:

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

однако, если собственность не объявлен как виртуальный, то вы можете использовать ключевое слово new, чтобы заменить его:

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

вы все еще можете использовать устаревший атрибут таким же образом, как если бы метод был переопределен, или вы можете бросить 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; }

в зависимости от того, был ли он объявлен или нет как виртуальный в базовом классе.


хотя технически свойство не будет скрыто, один из способов сильно препятствовать его использованию-это поместить на него такие атрибуты:

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]

вот какая система.Окна.Формы для элементов управления, которые имеют свойства, которые не вписываются. The текст свойство, например, находится на Control, но это не имеет смысла для каждого класса, который наследует от Control. Так, например, в MonthCalendar это выглядит следующим образом (per Рефлектор):

[Browsable(false), Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
    EditorBrowsable(EditorBrowsableState.Never)]
public override string Text
{
    get { return base.Text; }
    set { base.Text = value; }
}

Browsable указывает, отображается ли элемент в окне Свойства. EditorBrowsable указывает, отображается ли он в раскрывающемся списке Intellisense. Вы все равно можете ввести свойство, если EditorBrowsable имеет значение false, и оно все равно будет строиться, но не будет так очевидно, что вы можете его использовать.


просто скрывает это

 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;
    }
}

Примечание: Name по-прежнему будет открытым членом ClassBase, учитывая ограничение не изменять базовый класс, нет способа остановить это.


зачем форсировать наследование, когда это не нужно? Я думаю, что правильный способ сделать это, выполнив 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;
    }
}

Я не думаю, что многие люди, отвечающие здесь, понимают наследование вообще. Существует необходимость наследовать от базового класса и скрывать его когда-то общедоступные var и функции. Например, предположим, у вас есть базовый двигатель, и вы хотите сделать новый двигатель с наддувом. Ну, 99% двигателя вы будете использовать, но вы подправить немного его функциональность, чтобы сделать его намного лучше и все же есть некоторые возможности, которые должны быть показаны внесенные изменения, а не конец пользователь. Потому что мы все знаем, что каждый класс MS выпускает на самом деле никогда не нуждается в каких-либо модификациях.

Помимо использования нового, чтобы просто переопределить функциональность, это одна из вещей, которые Microsoft в их бесконечном wis..... О, я имею в виду, что ошибки считаются инструментом, который больше не стоит.

лучший способ сделать это сейчас-это многоуровневое наследование.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

класс B выполняет всю вашу работу, А Класс C предоставляет то, что вам нужно.


Я полностью согласен с тем, что свойства не должны удаляться из базовых классов, но иногда производный класс может иметь другой более подходящий способ ввода значений. В моем случае, например, я наследую от ItemsControl. Как мы все знаем, ItemsControl имеет свойство ItemsSource, но я хочу, чтобы мой элемент управления объединял данные из 2 источников (например, Person и Location). Если бы я хотел, чтобы пользователь вводил данные с помощью ItemsSource, мне нужно было бы отделить, а затем рекомбинировать значения, поэтому я создал 2 свойства для ввода данных. Но вернемся к исходному вопросу, это оставляет ItemsSource, который я не хочу, чтобы пользователь использовал, потому что я "заменяю" его своими собственными свойствами. Мне нравятся идеи Browsable и EditorBrowsable, но это все равно не мешает пользователю использовать его. Основной момент здесь заключается в том, что наследование должно сохранять большинство свойств, но когда есть большой сложный класс (особенно те, где вы не можете изменить исходный код), перезапись все было бы очень неэффективно.


вы не можете, в этом весь смысл наследования: подкласс должен предлагать все методы и свойства базового класса.

вы можете изменить реализацию, чтобы вызвать исключение при вызове свойства (если оно было виртуальным)...


Я думаю, что это плохой дизайн, Если вам нужно это сделать, особенно если вы можете спроектировать код с нуля.

Почему?

хороший дизайн-позволить базовому классу делиться общими свойствами, которые имеет определенная концепция (виртуальная или реальная). Пример: System.ИО.Поток в C#.

далее по переулку плохой дизайн увеличит стоимость обслуживания и сделает реализацию все сложнее и сложнее. Избежать этого как можно больше!

Основные правила который я использую:

  • минимизировать количество свойств и методов базового класса. Если вы не ожидаете использовать некоторые свойства или методы в классе, наследующем базовый класс, не помещайте его в базовый класс. Если вы находитесь в стадии разработки проекта; всегда возвращайтесь к чертежной доске, чтобы проверить дизайн, потому что все меняется! При необходимости перепроектировать. Когда ваш проект жив, затраты на изменение вещей позже в дизайне пойдут вверх!

    • Если вы используете базовый класс, реализованный 3-й стороной, рассмотрите возможность "подняться" на один уровень вместо " переопределения "с помощью" NotImplementedException " или такого. Если нет другого уровня, рассмотрите возможность разработки кода с нуля.

    • Всегда считайте, чтобы запечатать классы, которые вы не хотите, чтобы кто-то мог наследовать его. Это заставляет кодеров "подниматься на один уровень" в "иерархии наследования" и, таким образом, "свободные концы", такие как "NotImplementedException", могут следует избегать.


Я знаю, что вопрос старый, но вы можете переопределить 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");
    }