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.
Danke Adam :) Das war wirklich hilfreich. – DotNetGuy
@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. –