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".
Gracias Adam :) Eso fue realmente útil. – DotNetGuy
@DotNetGuy: Gracias; si esto responde su pregunta, recuerde marcarla como su respuesta aceptada para que otros puedan encontrar la respuesta más fácilmente. –