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上编译),我得到以下编译时错误 -
错误1无法访问受保护的成员 'BaseClass.BaseMethod()'通过 'BaseClass'类型的限定符;该 限定符必须是类型 'DerivedClass'(或从中衍生出来)
有人可以解释这种行为吗?这里出现了根本性的错误!
答案 0 :(得分:15)
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,
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.
}
}
虽然你提出的东西看起来很简单,如果它被允许发生,那么你在这里看到的那种恶作剧是可能的。现在,您知道受保护的方法调用来自您的类型(您可以控制)或来自您直接继承的类(您在编译时知道)。如果它对从继承声明类型继承的任何人开放,那么你将无法确定知道可以调用受保护方法的类型。
当您将BaseClass
变量初始化为您自己类的实例时,编译器只会看到该变量的类型为BaseClass
,从而使您置于信任圈之外。编译器不会分析所有赋值调用(或潜在的赋值调用)以确定它是否“安全”。
答案 1 :(得分:2)
来自C#规范:
受保护的实例成员是 在程序文本之外访问 声明它的类,和 当受保护的内部实例时 会员在该计划之外访问 它所在的程序的文本 声明,访问是必需的 通过一个实例发生 派生类访问的类型 发生。
MSDN链接here。
答案 2 :(得分:1)
这是直接从MSDN获取的:http://msdn.microsoft.com/en-us/library/bcd5672a%28VS.71%29.aspx
只有通过派生类类型进行访问时,才能在派生类中访问基类的受保护成员。例如,请考虑以下代码段:
class A
{
protected int x = 123;
}
class B : A
{
void F()
{
A a = new A();
B b = new B();
a.x = 10; // Error
b.x = 10; // OK
}
}