¿Cómo ocultar una propiedad heredada en una clase sin modificar la clase heredada (clase base)?


Si tengo el siguiente ejemplo de código:

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

¿Qué debo hacer para ocultar la propiedad Name (No se muestra como miembro de los miembros de ClassA) sin modificar ClassBase ?

Author: Mark, 2009-12-09

9 answers

Huelo un olor a código aquí. Es mi opinión que solo deberías heredar una clase base si estás implementando toda la funcionalidad de esa clase base. Lo que estás haciendo realmente no representa los principios orientados a objetos correctamente. Por lo tanto, si desea heredar de su base, debe implementar Name, de lo contrario, tendrá su herencia de la manera equivocada. Tu clase A debe ser tu clase base y tu clase base actual debe heredar de A si eso es lo que quieres, no al revés.

Sin embargo, no alejarse demasiado de la pregunta directa. Si querías burlar "las reglas" y quieres continuar en el camino que has elegido, así es como puedes hacerlo:

La convención es implementar la propiedad pero lanzar una NotImplementedException cuando se llama a esa propiedad - aunque, no me gusta eso tampoco. Pero esa es mi opinión personal y no cambia el hecho de que esta convención todavía destacar.

Si está intentando obsoleta la propiedad (y se declara en la clase base como virtual), entonces puede usar el atributo Obsolete en ella:

[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: Como Brian señaló en los comentarios, el segundo parámetro del atributo causará un error de compilador si alguien hace referencia a la propiedad Name, por lo que no podrá usarlo aunque lo haya implementado en la clase derivada.)

O como he mencionado uso NotImplementedException:

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

Sin embargo, si la propiedad no es declarada como virtual, entonces puede usar la nueva palabra clave para reemplazarla:

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

Todavía puede usar el atributo Obsolete de la misma manera que si el método se sobrescribiera, o puede lanzar la excepción NotImplementedException, lo que elija. Probablemente usaría:

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

O:

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

Dependiendo de si se declaró o no como virtual en la clase base.

 50
Author: BenAlabaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-09 12:10:55

Aunque técnicamente la propiedad no se ocultará, una forma de desalentar fuertemente su uso es ponerle atributos como estos:

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

Esto es lo que el Sistema.Windows.Forms hace para controles que tienen propiedades que no encajan. La propiedad Text, por ejemplo, está en Control, pero no tiene sentido en cada clase que hereda de Control. Así que en MonthCalendar, por ejemplo, aparece así (por reflector):

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

Navegable indica si el miembro aparece en la ventana de propiedades. EditorBrowsable indica si aparece en el menú desplegable Intellisense. Aún puede escribir la propiedad si EditorBrowsable está establecido en false, y aún se compilará, pero no será tan obvio que pueda usarla.

 27
Author: Ryan Lundy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-09 18:01:29

Solo escóndelo

 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: Name seguirá siendo un miembro público de ClassBase, dada la restricción de no cambiar la clase base, no hay forma de detenerlo.

 22
Author: CCondron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-20 10:59:32

¿Por qué forzar la herencia cuando no es necesario? Creo que la forma correcta de hacerlo es haciendo ha a en lugar de es-.

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;
    }
}
 4
Author: flayn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-27 13:36:47

No creo que mucha de la gente que responde aquí entienda la herencia en absoluto. Hay una necesidad de heredar de una clase base y ocultar sus var y funciones una vez públicas. Por ejemplo, digamos que tienes un motor básico y quieres hacer un nuevo motor que esté sobrealimentado. Bueno, el 99% del motor que va a utilizar, pero va a ajustar un poco de su funcionalidad para que funcione mucho mejor y sin embargo todavía hay alguna funcionalidad que solo se debe mostrar a las modificaciones realizadas, no al usuario final. Porque todos sabemos que cada clase que EM pone realmente no necesita ninguna modificación.

Además de usar el nuevo para simplemente anular la funcionalidad es una de las cosas que Microsoft en su infinito wis..... oh, me refiero a los errores considerados una herramienta que ya no vale la pena.

La mejor manera de lograr esto ahora es la herencia multinivel.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

La clase B hace todo su trabajo y la clase C expone lo que necesita expuesto.

 3
Author: engnrman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-09 07:53:40

Estoy completamente de acuerdo en que las propiedades no deben eliminarse de las clases base, pero a veces una clase derivada puede tener una forma diferente y más apropiada de ingresar los valores. En mi caso, por ejemplo, estoy heredando de ItemsControl. Como todos sabemos, ItemsControl tiene la propiedad ItemsSource, pero quiero que mi control combine datos de 2 fuentes (por ejemplo, Persona y Ubicación). Si tuviera que hacer que el usuario ingrese los datos usando ItemsSource, tendría que separar y luego recombinar el valores, así que he creado 2 propiedades para introducir los datos. Pero volviendo a la pregunta original, esto deja el ItemsSource, que no quiero que el usuario use porque lo estoy "reemplazando" con mis propias propiedades. Me gustan las ideas Navegables y EditorBrowsable, pero aún así no impide que el usuario lo use. El punto básico aquí es que la herencia debe mantener la MAYORÍA de las propiedades, pero cuando hay una clase compleja grande (especialmente aquellas donde no se puede modificar el código original), reescribir todo sería muy ineficiente.

 2
Author: Nathan Sokalski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-18 19:43:06

No se puede, ese es el punto de la herencia: la subclase debe ofrecer todos los métodos y propiedades de la clase base.

Puede cambiar la implementación para lanzar una excepción cuando se invoca la propiedad (si fuera virtual)...

 1
Author: Fried Hoeben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-09 17:17:14

Creo que es un mal diseño si tienes que hacer esto, especialmente si eres capaz de diseñar el código desde cero.

¿Por qué?

Un buen diseño consiste en permitir que la clase base comparta las propiedades comunes que tiene un determinado concepto (virtual o real). Ejemplo: System. IO. Stream en C#.

Más adelante, el mal diseño aumentará el costo de mantenimiento y hará que la implementación sea cada vez más difícil. Evitar esto tanto como sea posible!

Reglas básicas que I uso:

  • Minimizar el número de propiedades y métodos en la clase base. Si no espera usar algunas propiedades o métodos en una clase que hereda la clase base, entonces no lo coloque en la clase base. Si usted está en la etapa de desarrollo de un proyecto; siempre volver a la mesa de dibujo ahora y entonces para comprobar el diseño porque las cosas cambian! Rediseño cuando sea necesario. Cuando su proyecto está en marcha, los costos para cambiar las cosas más adelante en el diseño irán ¡arriba!

    • Si está utilizando una clase base implementada por una parte 3: rd, considere "subir" un nivel en lugar de "anular" con "NotImplementedException" o tal. Si no hay otro nivel, considere diseñar el código desde cero.

    • Siempre considere sellar las clases que no desea que nadie pueda heredarlo. Obliga a los codificadores a "subir un nivel" en la "jerarquía de herencia" y por lo tanto "cabos sueltos" como "NotImplementedException" puede ser evitar.

 0
Author: user3567581,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-24 07:20:48

Sé que la pregunta es antigua, pero lo que puedes hacer es anular las propiedades PostFilter 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");
    }
 0
Author: Nane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-14 16:51:44