2010-01-21 2 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 ? 
    } 
} 

In dem obigen Code (auf VS2005 kompiliert), ich die folgenden Compile Zeitfehler erhalten -Zurück zu den Wurzeln - C# Compiler Error

Fehler 1 nicht geschütztes Mitglied ‚BaseClass.BaseMethod() zugreifen kann 'über einen Qualifier des Typs' BaseClass '; die Qualifier muss vom Typ sein ‚DerivedClass‘ (oder daraus abgeleitet)

Kann jemand dieses Verhalten erklären? Hier läuft etwas grundsätzlich falsch!

Antwort

15

Eric Lippert nur blogged on this very topic.

Der grundlegende Kern davon ist sicherzustellen, dass eine Klasse dem Aufrufer einer geschützten Methode "vertrauen" kann. Klassen, die eine gemeinsame Basisklasse teilen - selbst wenn diese gemeinsame Basis die geschützte Methode definiert - sind in dieser Hinsicht im Wesentlichen Fremde.

Eric's Beispiel basiert auf der Idee einer Bankanwendung. Anstatt sein Beispiel neu zu erstellen, werde ich es gerade hier erbrechen:

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

Während das, was Sie präsentieren wie ein Kinderspiel scheint, wenn es dann die Art von Spielereien passieren durften Sie hier sehen, wäre möglich. Im Augenblick wissen Sie , dass ein Aufruf einer geschützten Methode entweder von Ihrem Typ (den Sie kontrollieren) oder von einer Klasse stammt, von der Sie direkt erben (die Sie zum Zeitpunkt der Kompilierung kennen). Wenn es für jeden geöffnet wäre, der vom deklarierenden Typ geerbt hat, dann hätten Sie nie die Sicherheit, die Typen zu kennen, die Ihre geschützte Methode aufrufen können.

Während Sie Ihre BaseClass -Variable zu einer Instanz Ihrer eigenen Klasse initialisieren, sieht der Compiler nur, dass die Variable vom Typ BaseClass ist, wodurch Sie außerhalb des Vertrauenskreises sind. Der Compiler analysiert nicht alle Zuweisungsaufrufe (oder mögliche Zuordnungsaufrufe), um festzustellen, ob es "sicher" ist.

+0

Danke Adam :) Das war wirklich hilfreich. – DotNetGuy

+0

@DotNetGuy: Danke; Wenn dies Ihre Frage beantwortet, denken Sie daran, sie als Ihre akzeptierte Antwort zu markieren, damit andere die Antwort leichter finden können. –

2

Von dem C# spec:

Wenn ein geschützten Instanz Mitglied außerhalb des Programmtextes von die Klasse, in der sie deklariert ist, und zugegriffen wird, wenn ein geschütztes internes Instanz Mitglied außerhalb des Zugriff auf Programm Text des Programms, in dem es deklariert ist, ist der Zugriff erforderlich, um durch eine Instanz der abgeleiteten Klassenart stattfinden, in der der Zugriff auftritt.

MSDN-Verbindung here.

1

Dies wird direkt von MSDN genommen: http://msdn.microsoft.com/en-us/library/bcd5672a%28VS.71%29.aspx

Geschütztes Mitglied einer Basisklasse ist nur in einer abgeleiteten Klasse zugänglich, wenn der Zugriff erfolgt durch die abgeleitete Klasse Typ erfolgt. Betrachten Sie zum Beispiel das folgende Codesegment:

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