C# - públicamente los métodos heredados estar ocultos (por ejemplo,privada a la clase derivada)

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

  •  01-07-2019
  •  | 
  •  

Pregunta

Supongamos que tengo BaseClass con público de los métodos a y B, y creo DerivedClass a través de la herencia.

por ejemplo,

public DerivedClass : BaseClass {}

Ahora quiero desarrollar un método de C en DerivedClass que utiliza a y B.Hay una manera que puedo reemplazar los métodos a y B para ser privado de DerivedClass de modo que sólo el método C está expuesto a alguien que quiere usar mi DerivedClass?

¿Fue útil?

Solución

No es posible, ¿por qué?

En C#, es forzado a usted que si usted hereda métodos públicos, debe hacerlos públicos.De lo contrario, se espera que no se derivan de la clase en el primer lugar.

En lugar de utilizar la es-una relación, tendría que utilizar la tiene-una relación.

El lenguaje de los diseñadores no permitir que esto a propósito, por lo que utilizar la herencia más adecuadamente.

Por ejemplo, uno podría accidentalmente confundir una clase de Coche que se derivan de una clase de Motor para obtener su funcionalidad.Pero un Motor es una funcionalidad que se utiliza en el coche.Por lo que se quiere para el uso de la ha-una relación.El usuario del Coche no quiere tener acceso a la interfaz del Motor.Y el Coche en sí no debe confundir el Motor de métodos con la que es propia.Ni el Coche del futuro derivaciones.

Así que no le permiten protegerse de los malos las jerarquías de herencia.

¿Qué debe hacer en su lugar?

En lugar usted debe implementar interfaces.Esto te deja libre para tener la funcionalidad mediante la tiene-una relación.

Otros idiomas:

En C++ simplemente especificar un modificador antes de la base de la clase de públicos, privados o protegidos.Esto hace que todos los miembros de la base de que eran de público a la que se especifica el nivel de acceso.Parece una tontería para mí que usted no puede hacer lo mismo en C#.

El proceso de reestructuración de código:

interface I
{
    void C();
}

class BaseClass
{
    public void A() { MessageBox.Show("A"); }
    public void B() { MessageBox.Show("B"); }
}

class Derived : I
{
    public void C()
    {
        b.A();
        b.B();
    }

    private BaseClass b;
}

Entiendo que los nombres de las clases superiores son un poco discutible :)

Otras sugerencias:

Otros han sugerido hacer Un() y B() pública y lanzar excepciones.Pero esto no hace que un amistoso de la clase para que la gente use y que en realidad no hacen sentido.

Otros consejos

Cuando, por ejemplo, se intenta heredar de una List<object>, y desea ocultar el directo Add(object _ob) miembro de:

// the only way to hide
[Obsolete("This is not supported in this class.", true)]
public new void Add(object _ob)
{
    throw NotImplementedException("Don't use!!");
}

Realmente no es la mejor solución, pero hace el trabajo.Intellisense todavía acepta, pero en tiempo de compilación con un error:

error CS0619:'TestConsole.TestClass.Agregar(TestConsole.TestObject)' es obsoleto:'Esto no es posible en esta clase".

Eso suena como una mala idea. Liskov no se impresionó.

Si no quieren que los consumidores de DerivedClass a ser capaz de acceder a métodos DeriveClass.Un() y DerivedClass.B() yo sugeriría que DerivedClass debe implementar algunas interfaz pública IWhateverMethodCIsAbout y los consumidores de DerivedClass en realidad debería estar hablando con IWhateverMethodCIsAbout y no saben nada acerca de la implementación de la clase base o DerivedClass a todos.

Lo que usted necesita es la composición no la herencia.

class Plane
{
  public Fly() { .. }
  public string GetPilot() {...}
}

Ahora bien, si usted necesita un tipo especial de Plano, como el que ha PairOfWings = 2, pero de lo contrario, hace todo lo que un avión puede..Se hereda plano.Por el presente usted declara que su derivación cumple con el contrato de la clase base y puede ser sustituido sin pestañear cuando una clase base que se espera.por ejemplo,LogFlight(Plano) continuará trabajando con un Biplano de la instancia.

Sin embargo, si usted simplemente necesita el comportamiento de la Mosca para un nuevo Pájaro desea crear y no están dispuestos a apoyar a la completa base de la clase de contrato, se componen en su lugar.En este caso, refactorizar el comportamiento de los métodos para reutilizar en un nuevo tipo de Vuelo.Ahora crear y mantener las referencias a esta clase, tanto en el Plano y de Aves.No se hereda, porque el Pájaro no apoyo la completa base de la clase de contrato...( por ejemplo,no puede proporcionar GetPilot() ).

Por la misma razón, usted puede reducir la visibilidad de la base de los métodos de la clase cuando se reemplaza.. usted puede anular y hacer una base de método privado público en la derivación, pero no viceversa.por ejemplo,En este ejemplo, si yo derivar un tipo de Avión "BadPlane" y, a continuación, reemplazar y "Ocultar" GetPilot() - hacer lo privado;un método del cliente LogFlight(Plano p) funcionará para la mayoría de los Aviones, sino que va a explotar para "BadPlane" si la aplicación de LogFlight sucede a la necesidad de llamar a GetPilot(). Desde todas las derivaciones de una clase base se espera que para ser "sustituibles" siempre que sea una clase base param es de esperar, esto ha de ser desestimado.

La única manera de hacer esto, que yo sepa, es el uso de un Ha-Una relación y sólo implementar las funciones que desea exponer.

@Brian R.Bondy me señaló un artículo interesante en el hecho de Ocultar a través de la herencia y la nuevo la palabra clave.

http://msdn.microsoft.com/en-us/library/aa691135(VS.71).aspx

Así que como solución sugeriría:

class BaseClass
{
    public void A()
    {
        Console.WriteLine("BaseClass.A");
    }

    public void B()
    {
        Console.WriteLine("BaseClass.B");
    }
}

class DerivedClass : BaseClass
{
    new public void A()
    {
        throw new NotSupportedException();
    }

    new public void B()
    {
        throw new NotSupportedException();
    }

    public void C()
    {
        base.A();
        base.B();
    }
}

De esta forma el código como este se tiro de un NotSupportedException:

    DerivedClass d = new DerivedClass();
    d.A();

La clandestinidad es un muy resbaladiza pendiente.Las principales cuestiones que, en mi opinión, son:

  • Es dependiente del tiempo de diseño la declaración de tipo de la instancia, es decir, si haces algo como BaseClass obj = new Subclase(), entonces llame obj.Un(), ocultando es derrotado.BaseClass.Un() será ejecutada.

  • Ocultar muy fácilmente puede ocultar comportamiento (o cambios de comportamiento) en el tipo base.Esta es, obviamente, menos de una preocupación cuando usted es dueño de lados de la ecuación, o si la llamada 'base.xxx' es parte de su sub-afiliado.

  • Si usted realmente ¿ propias ambos lados de la base/sub-clase de la ecuación, entonces usted debe ser capaz de diseñar una más manejable solución que institucionalizadas ocultar/sombreado.

Yo diría que si usted tiene una base de código que están queriendo hacer esto, no es el mejor diseñado de la base de código.Es generalmente un signo de una clase en un nivel de la jerarquía necesidad de un determinado público de la firma, mientras que otra clase derivada de la clase no las necesita.

Un próximo paradigma de codificación se denomina "Composición a lo largo de la Herencia". Esto juega directamente de los principios de desarrollo orientado a objetos (especialmente el Principio de Responsabilidad Único y Abierto/Cerrado de Principio).

Por desgracia, la forma en que muchos de nosotros los desarrolladores enseñaron la orientación a objetos, hemos formado un hábito de inmediato el pensamiento acerca de la herencia en lugar de la composición.Tendemos a tener más clases que tienen muchas responsabilidades diferentes simplemente porque pueden ser contenidos con el mismo "Mundo Real" del objeto.Esto puede conducir a la clase de las jerarquías que son 5+ niveles de profundidad.

Un desafortunado efecto secundario que los desarrolladores no suelen pensar en el momento de lidiar con la herencia es que la herencia constituye una de las formas más fuertes de las dependencias que nunca se puede introducir en el código.La clase derivada ahora es fuertemente dependiente de la clase a la que fue heredado de.Esto puede hacer que el código sea más frágil en el largo plazo y llevar a la confusión de los problemas que el cambio de un determinado comportamiento en una clase base rompe las clases derivadas de oscuros caminos.

Una forma de romper el código de seguridad es a través de interfaces como se mencionó en otra respuesta.Esto es una cosa inteligente a hacer de todos modos como usted desea que una clase de dependencias externas para enlazar a las abstracciones, no es concreto/tipos derivados.Esto le permite cambiar de la aplicación sin necesidad de cambiar la interfaz, sin necesidad de efectuar una línea de código en su clase dependiente.

Me gustaría mucho más que para mantener un sistema con cientos/miles/incluso más clases que son todos pequeños y débilmente acoplados, de acuerdo con un sistema que hace uso intensivo de polimorfismo/herencia y tiene menos clases que están más estrechamente acoplados.

Tal vez el mejor de recursos hacia fuera allí en el desarrollo orientado a objetos es Robert C.Martin del libro, Ágil de Desarrollo de Software, Principios, Patrones y Prácticas, y.

Si son públicos definidos en la clase original, no se puede reemplazar a ser privado en la clase derivada.Sin embargo, usted podría hacer que el público sea el método de lanzar una excepción y aplicar su propia función.

Editar:Jorge Ferreira es correcta.

Mientras que la respuesta a la pregunta es "no", no es una sugerencia, deseo señalar que para otros que llegan aquí (dado que el OP era una especie de alusión a la asamblea de acceso por 3 de las partes).Cuando los demás hacer referencia a un ensamblado, Visual Studio debe honrar el siguiente atributo de modo que no se muestran en intellisense (oculto, pero TODAVÍA puede ser llamado, así que ten cuidado):

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

Si usted no tenía ninguna otra opción, usted debería ser capaz de utilizar new en un método que se esconde un tipo de base de método, de retorno => throw new NotSupportedException();, y combinarlo con el atributo anterior.

Otro truco depende de NO heredar de una clase base, si es posible, donde la base tiene una interfaz correspondiente (tales como IList<T> para List<T>).La implementación de interfaces "explícitamente" también se esconden los métodos de intellisense en el tipo de clase.Por ejemplo:

public class GoodForNothing: IDisposable
{
    void IDisposable.Dispose() { ... }
}

En el caso de var obj = new GoodForNothing(), el Dispose() método no estará disponible en obj.Sin embargo, ESTARÁ disponible para cualquier persona que de forma explícita el tipo de retransmisiones obj a IDisposable.

Además, también se puede envolver un tipo de base en lugar de heredar de él, a continuación, ocultar algunos métodos:

public class MyList<T> : IList<T>
{
    List<T> _Items = new List<T>();
    public T this[int index] => _Items[index];
    public int Count => _Items.Count;
    public void Add(T item) => _Items.Add(item);
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    void ICollection<T>.Clear() => throw new InvalidOperationException("No you may not!"); // (hidden)
    /*...etc...*/
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top