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 ? 
    } 
} 

Nel codice di cui sopra (compilato su VS2005), ottengo il seguente errore di compilazione Tempo -Ritorno alle origini - C# Errore del compilatore

di errore 1 Impossibile accedere membro protetto 'BaseClass.BaseMethod() 'tramite un qualificatore di tipo' BaseClass '; il qualificatore deve essere di tipo 'DerivedClass' (o da esso derivato)

qualcuno può spiegare questo comportamento? Qui sta fondamentalmente qualcosa di sbagliato!

risposta

15

Eric Lippert solo blogged on this very topic.

L'essenza di base è garantire che una classe possa "fidarsi" del chiamante di un metodo protetto. Le classi che condividono una classe base comune - anche se quella base comune definisce il metodo protetto - sono essenzialmente estranee a questo riguardo.

L'esempio di Eric si basa sull'idea di un'applicazione bancaria. Invece di ricreare il suo esempio, mi limiterò a rigurgitare qui:

// 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. 
    } 
} 

mentre ciò che si presenti sembra un gioco da ragazzi, se fosse permesso che accada, allora il genere di imbrogli che vedete qui sarebbe possibile. In questo momento è sapere che una chiamata al metodo protetto proviene dal tipo (di cui si ha il controllo) o da una classe da cui si eredita direttamente (che si conosce al momento della compilazione). Se fosse aperto a chiunque avesse ereditato dal tipo dichiarante, non avresti mai la certezza di conoscere i tipi che possono chiamare il tuo metodo protetto.

Durante l'inizializzazione della variabile BaseClass in un'istanza della propria classe, il compilatore vede solo che la variabile è di tipo BaseClass, mettendoti al di fuori della cerchia della fiducia. Il compilatore non analizza tutte le chiamate di assegnazione (o potenziali chiamate di assegnazione) per determinare se è "sicuro".

+0

Grazie Adam :) È stato davvero utile. – DotNetGuy

+0

@DotNetGuy: Grazie; se questo risponde alla tua domanda, ricorda di contrassegnarla come risposta accettata in modo che gli altri possano trovare più facilmente la risposta. –

2

Dalla C# spec:

Quando un membro di istanza protetta è accede al di fuori del testo del programma di della classe in cui è dichiarata, e quando un interno membro di istanza protetta si accede al di fuori del programma testo del programma in cui è dichiarato , l'accesso è richiesto a avviene tramite un'istanza del tipo di classe derivata in cui si verifica l'accesso .

MSDN link here.

1

Ciò è presa direttamente da MSDN: http://msdn.microsoft.com/en-us/library/bcd5672a%28VS.71%29.aspx

Un membro protetto di una classe base è accessibile in una classe derivata solo se l'accesso avviene attraverso il tipo classe derivata. Ad esempio, considerare il seguente segmento di codice:

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 
    } 
} 
Problemi correlati