Como ocultar uma propriedade herdada de uma classe sem modificar a classe herdada (classe base)?

StackOverflow https://stackoverflow.com/questions/1875401

Pergunta

Se eu tenho o seguinte código de exemplo:

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

O que devo fazer para ocultar a propriedade Name (Não mostrado como um membro da ClassA membros), sem modificar ClassBase ?

Foi útil?

Solução

Sinto um cheiro de código aqui. É minha opinião que você deve herdar apenas uma classe base se estiver implementando toda a funcionalidade dessa classe base. O que você está fazendo realmente não representa os princípios orientados a objetos corretamente. Portanto, se você deseja herdar da sua base, deve implementar o nome, caso contrário, você tem sua herança da maneira errada. Sua classe A deve ser sua classe base e sua classe base atual deve herdar de um se for isso que você deseja, não o contrário.

No entanto, Não se afastar muito da questão direta. Se você fez Quer desrespeitar "as regras" e querer continuar no caminho que você escolheu - veja como você pode fazer isso:

A convenção deve implementar a propriedade, mas jogue uma notimplementException quando essa propriedade é chamada - embora eu também não goste disso. Mas essa é a minha opinião pessoal e não muda o fato de que esta convenção ainda permanece.

Se você está tentando obsoleto a propriedade (e ela é declarada na classe base como virtual), você pode usar o atributo obsoleto nela:

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

(Editar: Como Brian apontou nos comentários, o segundo parâmetro do atributo causará um erro do compilador se alguém referir a propriedade Name, portanto, não poderá usá -lo, mesmo que você o implemente na classe derivada.)

Ou, como mencionei, use no notimplementException:

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

No entanto, se a propriedade não é Declarado como virtual, você pode usar a nova palavra -chave para substituí -la:

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

Você ainda pode usar o atributo obsoleto da mesma maneira que se o método fosse substituído, ou você pode lançar a notimplementException, o que escolher. Eu provavelmente usaria:

[Obsolete("Don't use this", true)]
public override string Name { get; set; }

ou:

[Obsolete("Don't use this", true)]
public new string Name { get; set; }

Dependendo se foi declarado ou não como virtual na classe base.

Outras dicas

Embora tecnicamente a propriedade não esteja oculta, uma maneira de desencorajar fortemente seu uso é colocar atributos nela assim:

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

É isso que o System.Windows.Forms faz para os controles que possuem propriedades que não se encaixam. o Texto A propriedade, por exemplo, está sob controle, mas não faz sentido em todas as classes que herdam do controle. Então em MonthCalendar, por exemplo, a propriedade de texto aparece assim (de acordo com a fonte de referência on -line):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • Navegável - se o membro aparece na janela Propriedades
  • Editorbrowsable - se o membro aparece no suspensão do Intellisense

O EditorBrowsable (false) não impedirá que você digite a propriedade e, se você usar a propriedade, seu projeto ainda será compilado. Mas como a propriedade não aparece no Intellisense, não será tão óbvio que você pode usá -la.

Apenas esconda

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

Nota: O nome ainda será um membro público da ClassBase, dada a restrição de não alterar a classe base, não há como parar isso.

Por que forçar a herança quando não é necessária? Eu acho que a maneira correta de fazer isso é fazer tem um em vez de um é um.

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

Eu concordo completamente que as propriedades não devem ser removidos da base de dados de classes, mas, às vezes, uma classe derivada pode ter uma diferente forma mais adequada para introduzir os valores.No meu caso, por exemplo, eu sou de herdar de ItemsControl.Como todos nós sabemos, ItemsControl tem a propriedade ItemsSource, mas eu quero o meu controle para dados de impressão a partir de 2 fontes (por exemplo, Pessoa e Local).Se eu fosse para que o usuário digite os dados usando ItemsSource, eu precisaria separado e, em seguida, recombinar os valores, por isso criei 2 propriedades para inserir os dados.Mas, voltando a pergunta inicial, o que deixa o ItemsSource, que eu não quero que o utilizador utilize, porque eu sou "substituir" com os meus próprios estabelecimentos.Eu gosto do Navegável e EditorBrowsable idéias, mas, ainda assim, não impede o utilizador de usar.O ponto básico aqui é que a herança deve manter a MAIORIA das propriedades, mas quando há um grande complexo de classe (especialmente aquelas onde não é possível modificar o código original), reescrevendo tudo seria muito ineficiente.

Eu não acho que muitas pessoas respondendo aqui entendam a herança. É necessário herdar de uma classe base e ocultar suas varas e funções antes públicas. Por exemplo, digamos que você tenha um mecanismo básico e deseja criar um novo mecanismo que seja sobrealimentado. Bem, 99% do motor que você usará, mas você ajustará um pouco de sua funcionalidade para torná -lo muito melhor e, no entanto, ainda há alguma funcionalidade que só deve ser mostrada nas modificações feitas, não o usuário final. Porque todos sabemos que toda classe que a MS é realmente precisa de modificações.

Além de usar o novo para simplesmente substituir a funcionalidade, é uma das coisas que a Microsoft em seu infinito Wis… .. oh, quero dizer, erros considerados uma ferramenta que não vale mais a pena.

A melhor maneira de conseguir isso agora é a herança de vários níveis.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

A classe B faz todo o seu trabalho e a classe C expõe o que você precisa exposto.

Você não pode, esse é o ponto principal da herança: a subclasse deve oferecer todos os métodos e propriedades da classe base.

Você pode mudar a implementação para lançar uma exceção quando a propriedade for chamada (se fosse virtual) ...

Eu acho que é um design ruim se você precisar fazer isso, especialmente se você puder projetar o código desde o início.

Por quê?

O bom design é permitir que a classe base compartilhe propriedades comuns que um determinado conceito possui (virtual ou real). Exemplo: System.io.stream em C#.

Mais adiante, o design ruim da pista aumentará o custo de manutenção e tornará a implementação cada vez mais difícil. Evite isso o máximo possível!

Regras básicas que eu uso:

  • Minimize o número de propriedades e métodos na classe base. Se você não espera usar algumas propriedades ou métodos em uma classe que herda a classe base; Não coloque -o na base de base então. Se você estiver no desenvolvimento de um projeto; Sempre volte para o quadro de desenho agora e para verificar o design, porque as coisas mudam! Redesenhar quando necessário. Quando o seu projeto estiver ao vivo, os custos para mudar as coisas mais tarde no design aumentarão!

    • Se você estiver usando um grupo de base implementado por uma parte 3: RD, considere "subir" um nível em vez de "substituir" com "notimplementException" ou algo assim. Se não houver outro nível, considere projetar o código do zero.

    • Sempre considere selar as classes que você não deseja que alguém possa herdá -lo. Ele força os codificadores a "subir um nível" na "hierarquia de herança" e, portanto, "pontas soltas" como "notimplementException" podem ser evitadas.

Eu sei que a pergunta é antiga, mas o que você pode fazer é substituir as pós -filterproperties como esta:

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

Você pode usar Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top