Pregunta

Este código:

abstract class C
{
    protected abstract void F(D d);
}

class D : C
{
    protected override void F(D d) { }

    void G(C c)
    {
        c.F(this);
    }
}

genera este error:

  

No se puede acceder miembro protegido 'C.F (D)' a través de un calificador de tipo 'C'; el calificador debe ser de tipo 'D' (o derivada de ella)

Lo que en el mundo estaban pensando? (Habría que infringe la regla alterando algo?) Y es que hay una forma de evitar que aparte de hacer pública F?


Edit: Ahora recibe la razón de por qué esto es (Gracias Greg) pero todavía estoy un poco perplejo en cuanto a lo racional; dado:

class E : C
{
    protected override void F(D d) { }
}  

¿Por qué no debe D podrá ser capaz de llamar E.F?


El mensaje de error es editado por lo que podría haber puesto un error tipográfico en ese país.

¿Fue útil?

Solución

La palabra clave "protegido" significa que sólo un tipo y tipos que se derivan de ese tipo pueden tener acceso al miembro. D no tiene ninguna relación con C, por tanto, no puede acceder al miembro.

Usted tiene un par de opciones si usted quiere ser capaz de acceder a ese miembro

  • Que sea público
  • Que sea interno. Esto permitirá ningún tipo de acceso al miembro dentro del mismo conjunto (u otros montajes debe agregar de un amigo)
  • Derivar D de C

Editar

Este escenario se llama en la sección 3.5.3 de la especificación C #.

La razón de esto no está permitido es porque permitiría jerarquía para las llamadas cruzadas. Imagínese que, además de D, había otra clase de base de C llamado E. Si el código se podría compilar que permitiría D para acceder al EF miembro Este tipo de escenario no está permitido en C # (y I creen CLR pero sí sé no al 100%).

Edit2 ¿Por qué esto es malo

Advertencia, esta es mi opinión

La razón de esto ahora se permite es que hace que sea muy difícil para razonar acerca del comportamiento de una clase. El objetivo de modificadores de acceso es dar el control desarrollador sobre exactamente quién puede acceder a métodos específicos. Imagine la siguiente clase

sealed class MyClass : C {
  override F(D d) { ... } 
}

Considere lo que sucede si F es una función algo de tiempo crítico. Con el comportamiento actual que puedo razonar sobre la corrección de mi clase. Después de todo sólo hay dos casos en los que MiClase.f se llamará.

  1. Cuando se invoca en C
  2. Cuando invoco explícitamente en MyClass

Puedo examinar estas llamadas y llegar a una conclusión razonable sobre las funciones de la forma en MiClase.

Ahora, si C # sí permite jerarquía cruz acceso protegido Puedo hacer esa garantía. Cualquier persona en un montaje completamente diferente puede conseguir y derivar de C. Luego se puede llamar MiClase.f a voluntad. Esto hace que sea completamente imposible razonar sobre la corrección de mi clase.

Otros consejos

La razón de que esto no funciona es porque C # no permite la llamada cruzada jerarquía de métodos protegidos. Decir que no había un E clase que también deriva de C:

  C
 / \
D   E

A continuación, la referencia que está tratando de llamar al método en realidad podría ser una instancia de tipo E y por lo tanto el método podría resolver en tiempo de ejecución a E.F. Esto no está permitido en C # como D no puede llamar a los métodos protegidos de E, porque E está en otra rama de la jerarquía, es decir.

var d = new D();
var e = new E();
d.G(e); // oops, now this will call E.F which isn't allowed from D

Esto tiene sentido porque la palabra clave protected significa que el miembro de " es accesible dentro de su clase y las instancias de clase por derivados " y EF no es miembro de D.

A pesar de que D es hereda de C, D no puede acceder a los miembros protegidos de C. D puede acceder a los miembros D's protegida (y privada), así que si se pone otra instancia de D ahí en lugar de C todo saldría bien. Sin embargo, como se dijo Greg, C realmente podría ser algo completamente diferente, y debido a que el compilador no sabe lo que realmente es C, tiene que evitar que accedan a algo D D no puede realmente ser capaz de acceso.

Una serie de mensajes que explican esto desde la perspectiva del compilador de C #:

Esta limitación se puede evitar mediante el uso de un método protegido estática:

abstract class C
{
    protected abstract void F (D d);

    // Allows calling F cross-hierarchy for any class derived from C
    protected static void F (C c, D d)
    {
        c.F(d);
    }
}

class D : C
{
    protected override void F (D d) { }

    void G (C c)
    {
        // c.F(this);
        F(c, this);
    }
}

Esto no es perfecto desde el punto de vista de seguridad (cualquiera puede derivar de C), pero si lo único que importa es el método ocultar F de la interfaz pública de la clase C, este truco puede ser útil.

Para entender por qué este tipo de comportamiento tiene sentido vamos a considerar por qué necesitamos modificadores de acceso en absoluto en los lenguajes de programación orientados a objetos. Los necesitamos limitan a un ámbito donde un miembro de la clase particular, se puede utilizar . Y que a su vez simplifica la búsqueda de los usos.

Para resumir:

  • para encontrar todos los usos de miembro público uno tiene que buscar a través de todo el proyecto (y esto no es suficiente en el caso de la biblioteca que es utilizado por desarrolladores independientes)
  • para encontrar todos los usos de protegido miembro de uno tiene que buscar a través de la clase de contenedor y todas sus subclases
  • para encontrar todos los usos de miembro privado que uno tiene que buscar a través de la clase de contenedor .

Así que si el compilador permite llamar al método protegido de la superclase de la manera descrita podríamos terminar con llamadas cruzada jerarquía de métodos protegidos como se describe en esta respuesta . Y en tal situación había que buscar a través de todos los hijos de la clase más padres que define el miembro. Y eso sería aumentar el alcance.

PS. El mismo comportamiento se implementa en Java.

En pocas palabras: el acceso un miembro protegido de ejemplo, se toma como el acceso del público, incluso si se intenta hacerlo desde dentro de una clase derivada. Por lo tanto, se negó.


Hay muchas respuestas aquí y allí, pero ninguno de ellos lo hizo claro para mí "¿por qué no puedo acceder a los miembros protected de una clase padre de un niño". Que por encima es lo que entendí después de mirar en mi código de nuevo después de leer estas respuestas confusas.

Ejemplo:

class Parent
{
    protected int foo = 0;
}

// Child extends from Parent
class Child : Parent
{
    public void SomeThing(Parent p)
    {
        // Here we're trying to access an instance's protected member.
        // So doing this...
        var foo = p.foo;
    }
}

// (this class has nothing to do with the previous ones)
class SomeoneElse
{
    public void SomeThing(Parent p)
    {
        // ...is the same as doing this (i.e. public access).
        var foo = p.foo++;
    }
}

Uno pensaría que tendría acceso a p.foo porque estás dentro de una clase hija, pero que está accediendo a ella desde una instancia, y eso es como un acceso público, por lo que es negado.

Se le permite acceder a los miembros protected desde dentro de la clase, y no de una instancia (sí, sabemos que esto):

class Child : Parent
{
    public void SomeThing()
    {
        // I'm allowed to modify parent's protected foo because I'm
        // doing so from within the class.
        foo++;
    }
}

Por último, en aras de la exhaustividad, que son realmente capaces de acceder protected de una instancia y miembros incluso private sólo si se está haciendo para que dentro de la misma clase:

class Parent
{
    protected int foo = 0;

    private int bar = 0;

    public void SomeThing(Parent p)
    {
        // I'm allowed to access an instance's protected and private
        // members because I'm within Parent accessing a Parent instance
        var foo = p.foo;
        p.bar = 3;
    }
}

Sí, es posible. muy probablemente tendremos un ejemplo muy pronto.

Para hacer esto, usted debe hacer lo siguiente:

  1. La herencia del formulario predeterminado (EditAppointmentDialog) y hacer su personalización (incluso se puede utilizar el diseñador de Windows Forms para eso).

CustomAppointmentEditDialog clase parcial pública: EditAppointmentDialog     {         RadComboBox cmbShowTimeAs privada = null;

    public CustomAppointmentEditDialog() 
    { 
        InitializeComponent(); 

        this.cmbShowTimeAs = this.Controls["cmbShowTimeAs"] as RadComboBox; 
    } 

    private void chkConfirmed_ToggleStateChanged(object sender, StateChangedEventArgs args) 
    { 
        this.cmbShowTimeAs.SelectedValue = (args.ToggleState == ToggleState.On) ? 
            (int)AppointmentStatus.Busy : (int)AppointmentStatus.Tentative; 
    } 
} 

En el código anterior, he añadido una casilla de verificación adicionales y establecer el estado (tiempo muestran como) de la cita para tentativo si no está marcada como Ocupado, si está activada. La extraña forma de acceder al cuadro combinado se debe a que es privado actualmente. Esto puede cambiar para la próxima versión Q1 2009.

  1. Suscribirse a AppointmentEditDialogShowing caso de RadScheduler y sustituir el formulario predeterminado personalizado con su uno:

privada IEditAppointmentDialog appointmentEditDialog = null;

    protected override void OnLoad(EventArgs e) 
    { 
        base.OnLoad(e); 

        this.radScheduler1.AppointmentEditDialogShowing += new EventHandler<AppointmentEditDialogShowingEventArgs>(radScheduler1_AppointmentEditDialogShowing); 
    } 

    void radScheduler1_AppointmentEditDialogShowing(object sender, Telerik.WinControls.UI.AppointmentEditDialogShowingEventArgs e) 
    { 
        if (this.appointmentEditDialog == null) 
        { 
            this.appointmentEditDialog = new CustomAppointmentEditDialog(); 
        } 
        e.AppointmentEditDialog = this.appointmentEditDialog; 
    } 

Espero que esto ayude. No dude en escribir de nuevo si tiene más preguntas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top