polimorfico - herencia y polimorfismo c#
¿Cómo puedo ocultar una propiedad pública de la clase base en la clase derivada? (15)
Quiero ocultar la propiedad pública base (un miembro de datos) en mi clase derivada:
class Program
{
static void Main(string[] args)
{
b obj = new b();
obj.item1 = 4;// should show an error but it doent ???
}
}
class a
{
public int item1 {get; set;}
public int item2 { get; set; }
}
class b : a
{
new private int item1;
}
class c : a
{
}
Tengo un miembro como público porque quiero que el miembro sea heredado en la clase c, pero quiero ocultar el miembro en la clase b, ¿cómo puedo hacer esto?
¿No tengo una opción para heredar selectivamente la variable que quiero en mi clase base? Eso es realmente malo, creo que ms debería proporcionarnos una opción (puede ser un modificador) para realizar esto
Editar:
Encontré la respuesta yo mismo (escuché a muchos de ellos diciendo que esto no es posible en c #, pero puedes hacerlo)
Estoy incluyendo el código en caso de que sea útil
class Program
{
static void Main(string[] args)
{
b obj = new b();
obj.item1 = 4; // shows an error : )
}
}
class a
{
public int item1 { get; set; }
public int item2 { get; set; }
}
class b : a
{
new public static int item1
{
get;
private set;
}
}
Antes que nada, esto no es una buena idea si usas algunos métodos que operan en la clase base.
Puede intentar utilizar un argumento obsoleto para que los usuarios piensen dos veces en usar esta propiedad.
[System.Obsolete("Do not use this property",true)]
public override YourType YourProperty { get; set; }
Cambiar la accesibilidad de un miembro virtual es una clase heredada específicamente prohibida por la especificación del lenguaje C #:
La declaración de anulación y el método base anulado tienen la misma accesibilidad declarada. En otras palabras, una declaración de anulación no puede cambiar la accesibilidad del método virtual. Sin embargo, si el método de base anulado está protegido interno y se declara en un ensamblaje diferente que el ensamblado que contiene el método de anulación, entonces la accesibilidad declarada del método de anulación debe estar protegida.
De la sección 10.6.4 Anular métodos
Las mismas reglas que se aplican al método de anulación también se aplican a las propiedades, por lo que pasar de public
a private
al heredar de la clase base no se puede hacer en C #.
La respuesta de Vadim me recordó cómo la EM logra esto en el Marco en ciertos lugares. La estrategia general es ocultar el miembro de Intellisense utilizando el atributo EditorBrowsable . (NB Esto solo lo oculta si está en otro ensamblaje). Aunque no impide que nadie use el atributo, y pueden verlo si lo lanzan al tipo base (ver mi explicación previa) lo hace mucho menos visible ya que no aparece en Intellisense y mantiene la interfaz de la clase limpia.
Sin embargo, debería usarse con moderación, solo cuando otras opciones, como la reestructuración de la jerarquía de herencia, lo hagan mucho más complejo. Es un último recurso en lugar de la primera solución en la que pensar.
Lo único que se me ocurre es hacer que item1 sea virtual en la clase a:
class a
{
public virtual int item1 { get; set; }
public int item2 { get; set; }
}
y luego anularlo en la clase b pero lanzar una excepción en getter y setter. Además, si esta propiedad se utiliza en un diseñador visual, puede usar el atributo de búsqueda para no mostrarla.
class b : a
{
[Browsable(false)]
public override int item1
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
}
Lo que está describiendo es algo parecido a la "herencia privada" de C ++, y no está disponible en C #.
Lo que quiere hacer va directamente en contra del grano de OO, no puede "anular la publicación" de los miembros ya que esto viola el principio de sustitución. Tienes que refactorizar esto en otra cosa.
Lo que realmente necesitas son interfaces:
public interface ProvidesItem1
{
int item1 { get; set; }
}
public interface ProvidesItem2
{
int item2 { get; set; }
}
class a : ProvidesItem1, ProvidesItem2
{
public int item1 { get; set; }
public int item2 { get; set; }
}
class b : ProvidesItem1
{
public int item1 { get; set; }
}
Entonces simplemente pase las interfaces alrededor. Si las clases deben usar una implementación común, colóquela en una tercera clase y permítales derivar de esa clase así como implementar su respectiva interfaz.
No puede hacerlo directamente, pero puede anular las propiedades en la clase secundaria y hacerlas de solo lectura, por ejemplo
class Program
{
static void Main(string[] args)
{
b obj = new b();
obj.item1 = 4;// should show an error but it doent ???
}
}
class a
{
public virtual int item1 {get; set;}
public virtual int item2 { get; set; }
}
class b : a
{
public override int item1
{
get { return base.item1; }
set { }
}
}
class c : a
{
}
Podría usar interfaces para ocultar la propiedad. La clase secundaria implementaría una interfaz que no tenía la propiedad y luego no aparecería.
Necesitarás dos interfaces para cuando quieres la propiedad y cuando no, por lo que es un truco horrible.
Puede anularlo y luego agregar una etiqueta [Browsable (false)] para evitar que se muestre en el diseñador.
Sencillo:
public class a:TextBox
{
[Browsable(false)]
public override string Text
{
get { return ""; }
set { }
}
}
Sí, es posible. ¿Qué opinas sobre la delegación? Trataré de dar una idea de lo que se llama "delegación" en OOP con un fragmento de código:
public class ClassA
{
// public
public virtual int MyProperty { get; set; }
// protected
protected virtual int MyProperty2 { get; set; }
}
public class ClassB
{
protected ClassC MyClassC;
public ClassB()
{
MyClassC = new ClassC();
}
protected int MyProperty2
{
get { return MyClassC.MyProperty2; }
set { MyClassC.MyProperty2 = value; }
}
protected int MyProperty
{
get { return MyClassC.MyProperty; }
set { MyClassC.MyProperty = value; }
}
protected class ClassC : ClassA
{
public new int MyProperty2
{
get { return base.MyProperty2; }
set { base.MyProperty2 = value; }
}
public override int MyProperty
{
get { return base.MyProperty; }
set { base.MyProperty = value; }
}
}
}
Si quieres ocultar un miembro de la clase base, entonces necesitarás agregar una nueva clase base, vamos a llamarla baseA y tu código debería ser el siguiente:
Programa de clase {static void Main (cadena [] args) {b obj = new b (); obj.item1 = 4; // debería mostrar un error pero no ??? }}
class baseA
{
public int item2 { get; set; }
}
class a:baseA
{
public int item1 { get; set; }
}
class b : baseA
{
}
class c : a
{
}
Si usa una interfaz en lugar de una clase base para definir la propiedad, puede implementarla explícitamente. Se requeriría un lanzamiento explícito a la interfaz para usar la propiedad.
public interface IMyInterface
{
string Name { get; set; }
}
public class MyClass : IMyInterface
{
string IMyInterface.Name { get; set; }
}
Puedes encontrar más here .
Voy a intentar explicar con ejemplos por qué esta es una mala idea, en lugar de usar términos crípticos.
Su propuesta sería tener un código que se vea así:
public class Base
{
public int Item1 { get; set; }
public int Item2 { get; set; }
}
public class WithHidden : Base
{
hide Item1; // Assuming some new feature "hide" in C#
}
public class WithoutHidden : Base { }
Esto haría que el siguiente código no sea válido:
WithHidden a = new WithHidden();
a.Item1 = 10; // Invalid - cannot access property Item1
int i = a.Item1; // Invalid - cannot access property Item1
Y eso sería justo lo que querías. Sin embargo, supongamos que ahora tenemos el siguiente código:
Base withHidden = new WithHidden();
Base withoutHidden = new WithoutHidden();
SetItem1(withHidden);
SetItem1(withoutHidden);
public void SetItem1(Base base)
{
base.Item1 = 10;
}
El compilador no sabe qué tipo de tiempo de ejecución será la base de argumentos en SetItem1, solo que es al menos de tipo Base (o algún tipo derivado de Base, pero no puede decir cuál; puede ser obvio mirar el fragmento de código, pero los escenarios más complejos lo hacen prácticamente imposible).
Por lo tanto, el compilador no podrá, en un gran porcentaje de los casos, dar un error de compilación en el sentido de que Item1 es de hecho inaccesible. Entonces eso deja la posibilidad de un control en tiempo de ejecución. Cuando intente configurar Item1 en un objeto que es de hecho del tipo WithHidden arrojaría una excepción.
Ahora, al acceder a cualquier miembro, cualquier propiedad en cualquier clase no sellada (que es la mayoría de ellos) puede arrojar una excepción porque en realidad era una clase derivada que ocultó al miembro. Cualquier biblioteca que exponga cualquier tipo no sellado tendría que escribir un código defensivo al acceder a cualquier miembro solo porque alguien lo haya ocultado.
Una posible solución a esto es escribir la característica de modo que solo los miembros que se declaran ocultos puedan ser ocultados. El compilador no permitiría ningún acceso al miembro oculto en las variables de ese tipo (tiempo de compilación), y también incluiría verificaciones de tiempo de ejecución para que se lanzara una FieldAccessException si se lanzara al tipo base y se intentara acceder desde ese (runtime) .
Pero incluso si los desarrolladores de C # se tomaron la molestia y el costo de esta característica (recuerde, las características son caras , especialmente en el diseño del lenguaje), el código defensivo debe escribirse para evitar los posibles problemas de FieldAccessExceptions, así que ¿qué ventaja tiene? reorganizando su jerarquía de herencia ¿ha ganado? Con la nueva característica de ocultación de miembros, habría una gran cantidad de lugares potenciales para que los errores se infiltraran en su aplicación y bibliotecas, incrementando el tiempo de desarrollo y prueba.
namespace PropertyTest
{
class a
{
int nVal;
public virtual int PropVal
{
get
{
return nVal;
}
set
{
nVal = value;
}
}
}
class b : a
{
public new int PropVal
{
get
{
return base.PropVal;
}
}
}
class Program
{
static void Main(string[] args)
{
a objA = new a();
objA.PropVal = 1;
Console.WriteLine(objA.PropVal);
b objB = new b();
objB.PropVal = 10; // ERROR! Can''t set PropVal using B class obj.
Console.Read();
}
}
}