2010-01-21 18 views
6
public class BaseClass 
{ 
    protected void BaseMethod() 
    { 

    } 
} 

public class DerivedClass : BaseClass 
{ 
    public void Test() 
    { 
    DerivedClass d1 = new DerivedClass(); 
    d1.BaseMethod(); // No error here.   

    BaseClass b1 = new DerivedClass(); 
    b1.BaseMethod(); // I get compile-time error for this. Why ? 
    } 
} 

En el código anterior (recopilada en VS2005), me sale el siguiente error de tiempo de compilación -Volver a lo básico - C Error # compilador

de error 1 No se puede acceder miembro protegido 'BaseClass.BaseMethod() 'a través de un calificador del tipo' BaseClass '; la calificador debe ser de tipo 'DerivedClass' (o derivada de ella)

Puede alguien explicar este comportamiento? ¡Aquí algo está pasando fundamentalmente mal!

Respuesta

15

Eric Lippert just blogged on this very topic.

Lo esencial es garantizar que una clase pueda "confiar" en la persona que llama de un método protegido. Las clases que comparten una clase base común, incluso si esa base común define el método protegido, son esencialmente desconocidas a este respecto.

El ejemplo de Eric se basa en la idea de una aplicación bancaria. En lugar de volver a crear su ejemplo, sólo voy a regurgitan aquí:

// Good.dll: 

public abstract class BankAccount 
{ 
    abstract protected void DoTransfer(
    BankAccount destinationAccount, 
    User authorizedUser, 
    decimal amount); 
} 
public abstract class SecureBankAccount : BankAccount 
{ 
    protected readonly int accountNumber; 
    public SecureBankAccount(int accountNumber) 
    { 
    this.accountNumber = accountNumber; 
    } 
    public void Transfer(
    BankAccount destinationAccount, 
    User authorizedUser, 
    decimal amount) 
    { 
    if (!Authorized(user, accountNumber)) throw something; 
    this.DoTransfer(destinationAccount, user, amount); 
    } 
} 
public sealed class SwissBankAccount : SecureBankAccount 
{ 
    public SwissBankAccount(int accountNumber) : base(accountNumber) {} 
    override protected void DoTransfer(
    BankAccount destinationAccount, 
    User authorizedUser, 
    decimal amount) 
    { 
    // Code to transfer money from a Swiss bank account here. 
    // This code can assume that authorizedUser is authorized. 
    // We are guaranteed this because SwissBankAccount is sealed, and 
    // all callers must go through public version of Transfer from base 
    // class SecureBankAccount. 
    } 
} 
// Evil.exe: 
class HostileBankAccount : BankAccount 
{ 
    override protected void Transfer(
    BankAccount destinationAccount, 
    User authorizedUser, 
    decimal amount) { } 
    public static void Main() 
    { 
    User drEvil = new User("Dr. Evil"); 
    BankAccount yours = new SwissBankAccount(1234567); 
    BankAccount mine = new SwissBankAccount(66666666); 
    yours.DoTransfer(mine, drEvil, 1000000.00m); // compilation error 
    // You don't have the right to access the protected member of 
    // SwissBankAccount just because you are in a 
    // type derived from BankAccount. 
    } 
} 

Si bien lo que se presente parece una obviedad, si se permite que esto ocurra, entonces el tipo de chanchullos que se ve aquí sería posible. En este momento usted sabe que una llamada a método protegido proviene de su tipo (sobre el cual tiene control) o de una clase de la que hereda directamente (que usted sabe en el momento de compilar). Si se abriera a cualquiera que haya heredado del tipo de declaración, nunca tendrá la seguridad de conocer los tipos que pueden llamar a su método protegido.

Mientras inicializa su variable BaseClass a una instancia de su propia clase, el compilador solo ve que la variable es del tipo BaseClass, colocándolo fuera del círculo de confianza. El compilador no analiza todas las llamadas de asignación (o posibles llamadas de asignación) para determinar si es "seguro".

+0

Gracias Adam :) Eso fue realmente útil. – DotNetGuy

+0

@DotNetGuy: Gracias; si esto responde su pregunta, recuerde marcarla como su respuesta aceptada para que otros puedan encontrar la respuesta más fácilmente. –

2

Desde el C# spec:

Cuando un miembro de instancia protegido se accede fuera del texto de programa de la clase en la que se declara, y cuando se accede a un miembro de instancia interna protegida fuera de la programa texto del programa en el que se declara , se requiere el acceso a a través de una instancia del tipo de clase derivada en la que se produce el acceso .

enlace de MSDN here.

1

Esto se toma directamente de MSDN: http://msdn.microsoft.com/en-us/library/bcd5672a%28VS.71%29.aspx

Un miembro protegido de una clase base es accesible en una clase derivada sólo si el acceso tiene lugar a través del tipo de clase derivada. Por ejemplo, considere el siguiente segmento de código:

class A 
{ 
    protected int x = 123; 
} 

class B : A 
{ 
    void F() 
    { 
     A a = new A(); 
     B b = new B(); 
     a.x = 10; // Error 
     b.x = 10; // OK 
    } 
} 
Cuestiones relacionadas