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 ? } }
在上面的代码(在VS2005上编译),我得到以下编译时错误 –
Error 1 Cannot access protected member
‘BaseClass.BaseMethod()’ via a
qualifier of type ‘BaseClass’; the
qualifier must be of type
‘DerivedClass’ (or derived from it)
有人可以解释这种行为吗?这里有些根本错误!
解决方法@H_502_18@
Eric Lippert刚刚
blogged on this very topic.
它的基本要点是确保一个类可以“信任”受保护方法的调用者.共享一个公共基类的类 – 即使该公共基类定义了受保护的方法 – 在这方面基本上是陌生的.
Eric的例子基于银行应用程序的想法.而不是重新创建他的例子,我只会在这里反刍:
// 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,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,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,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.
}
}
虽然你提出的东西看起来很简单,如果它被允许发生,那么你在这里看到的那种恶作剧是可能的.现在您知道受保护的方法调用要么来自您的类型(您可以控制),要么来自您直接继承的类(您在编译时知道).如果它对从继承声明类型继承的任何人开放,那么你将无法确定知道可以调用受保护方法的类型.
当您将BaseClass变量初始化为您自己的类的实例时,编译器只会看到该变量的类型为BaseClass,使您置于信任圈之外.编译器不会分析所有分配调用(或潜在的分配调用)以确定它是否“安全”.
它的基本要点是确保一个类可以“信任”受保护方法的调用者.共享一个公共基类的类 – 即使该公共基类定义了受保护的方法 – 在这方面基本上是陌生的.
Eric的例子基于银行应用程序的想法.而不是重新创建他的例子,我只会在这里反刍:
// 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,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,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,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. } }
虽然你提出的东西看起来很简单,如果它被允许发生,那么你在这里看到的那种恶作剧是可能的.现在您知道受保护的方法调用要么来自您的类型(您可以控制),要么来自您直接继承的类(您在编译时知道).如果它对从继承声明类型继承的任何人开放,那么你将无法确定知道可以调用受保护方法的类型.
当您将BaseClass变量初始化为您自己的类的实例时,编译器只会看到该变量的类型为BaseClass,使您置于信任圈之外.编译器不会分析所有分配调用(或潜在的分配调用)以确定它是否“安全”.