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".
fonte
2010-01-21 16:23:00
Grazie Adam :) È stato davvero utile. – DotNetGuy
@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. –