Eric Lippert刚刚在他的博客上谈到了这个话题。
基本要点是确保一个类可以“信任”受保护方法的调用者。即使这个共同的基类定义了受保护的方法,共享一个共同基类的类在这方面本质上也是陌生人。
Eric的例子基于银行应用程序的想法。我不想重新创建他的示例,所以在这里我只会复述它:
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)
{
}
}
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);
}
}
虽然你所提出的似乎是一个不用多想的事情,但如果允许发生这种情况,那么你在这里看到的恶作剧就有可能发生。现在,你知道受保护的方法调用要么来自于你的类型(你可以控制),要么来自于你直接继承的类(在编译时你知道)。如果它向任何从声明类型继承的人开放,那么你将永远无法确定哪些类型可以调用你的受保护方法。
当你初始化一个BaseClass变量为自己类的实例时,编译器只看到变量是BaseClass类型,这使你处于信任圈之外。编译器不会分析所有赋值调用(或潜在的赋值调用)来确定它是否“安全”。