c# - polimorfismo - ¿Cómo ocultar una propiedad heredada en una clase sin modificar la clase heredada(clase base)?
que es override en c# (9)
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 el Name
la propiedad (No se muestra como miembro de los miembros de la Clase A) sin modificar ClassBase
?
¿Por qué forzar la herencia cuando no es necesario? Creo que la forma correcta de hacerlo es haciendo ha-a en vez de -is .
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;
}
}
Creo que es un mal diseño si tienes que hacer esto, especialmente si puedes diseñar el código desde cero.
¿Por qué?
Un buen diseño es permitir que la clase base comparta propiedades comunes que tiene cierto concepto (virtual o real). Ejemplo: System.IO.Stream en C #.
Más abajo en el carril, el mal diseño aumentará el costo de mantenimiento y hará que la implementación sea más y más difícil. ¡Evita esto tanto como sea posible!
Reglas básicas que uso:
Minimice 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; no lo pongas en la clase base entonces. Si estás en el desarrollo de un proyecto; ¡Siempre vuelva a la mesa de dibujo para verificar el diseño porque las cosas cambian! Rediseña cuando sea necesario. ¡Cuando su proyecto esté en vivo, los costos para cambiar las cosas más adelante en el diseño aumentarán!
Si está utilizando una clase base implementada por una parte 3: rd, considere "subir" un nivel en lugar de "anular" con "NotImplementedException" o similar. Si no hay otro nivel, considere diseñar el código desde cero.
Siempre considere sellar las clases que no desea que nadie pueda heredar. Obliga a los codificadores a "subir un nivel" en la "jerarquía de herencia" y así se pueden evitar "extremos sueltos" como "NotImplementedException".
Estoy completamente de acuerdo en que las propiedades no se deben eliminar de las clases base, pero a veces una clase derivada puede tener una forma diferente más apropiada para 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 quisiera que el usuario ingresara los datos usando ItemsSource, necesitaría separar y recombinar los valores, así que creé 2 propiedades para ingresar 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 explorables y editables, pero aún así no impide que el usuario lo use. El punto básico aquí es que la herencia debe mantener MÁS 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.
Huelo un olor a código aquí. En mi opinión, solo debería heredar una clase base si está 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, obtendrá su herencia al revés. Su clase A debería ser su clase base y su clase base actual debería heredar de A si eso es lo que desea, y no al revés.
Sin embargo, no alejarse demasiado de la pregunta directa. Si desea burlar "las reglas" y desea continuar en el camino que ha elegido, aquí le mostramos cómo puede hacerlo:
La convención es implementar la propiedad pero arrojar una excepción NotImplementedException cuando se llama a esa propiedad, aunque tampoco me gusta. Pero esa es mi opinión personal y no cambia el hecho de que esta convención sigue en pie.
Si intenta obsoleta la propiedad (y está declarada en la clase base como virtual), puede usar el atributo Obsoleto 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;
}
}
( Editar: Como señaló Brian en los comentarios, el segundo parámetro del atributo causará un error de compilación si alguien hace referencia a la propiedad Name, por lo que no podrán usarlo aunque lo hayas implementado en la clase derivada. )
O como mencioné, use NotImplementedException:
public override string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
Sin embargo, si la propiedad no se declara como virtual, 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 Obsoleto de la misma manera que si el método fue anulado, o puede lanzar la excepción NotImplementedException, cualquiera 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 fue o no declarado como virtual en la clase base.
No creo que muchas de las personas que responden aquí entiendan la herencia en absoluto. Existe la necesidad de heredar de una clase base y ocultar sus var y funciones una vez públicas. Por ejemplo, digamos que tiene un motor básico y desea crear un motor nuevo que esté sobrealimentado. Bueno, el 99% del motor que usará, pero ajustará un poco su funcionalidad para que funcione mucho mejor y aún así hay alguna funcionalidad que solo debería mostrarse a las modificaciones realizadas, no al usuario final. Porque todos sabemos que cada clase que MS saca no necesita modificaciones.
Además de usar lo nuevo para simplemente anular la funcionalidad, es una de las cosas que Microsoft en su infinita sabiduría ... oh, me refiero a los errores considerados una herramienta que ya no vale la pena.
La mejor forma de lograr esto ahora es la herencia multinivel.
public class classA
{
}
public class B : A
{}
public class C : B
{}
La clase B hace todo tu trabajo y la clase C expone lo que necesitas exponer.
No se puede, ese es el objetivo de la herencia: la subclase debe ofrecer todos los métodos y propiedades de la clase base.
Podría cambiar la implementación para lanzar una excepción cuando se llame a la propiedad (si fuera virtual) ...
Sé que la pregunta es antigua, pero lo que puedes hacer es anular las propiedades de 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");
}
Si bien técnicamente la propiedad no se ocultará, una forma de desalentar fuertemente su uso es ponerle atributos de la siguiente manera:
[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]
Esto es lo que hace System.Windows.Forms para los 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. Entonces 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 se muestra en el menú desplegable Intellisense. Aún puede escribir la propiedad si EditorBrowsable se establece en falso, y seguirá generando, pero no será tan obvio que puede usarlo.
Solo esconderlo
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: El nombre seguirá siendo un miembro público de ClassBase, dada la limitación de no cambiar la clase base, no hay forma de detener eso.