2010-01-21 45 views
6
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编译),我得到以下编译时错误 -回到基础 - C#编译器错误

错误1无法访问受保护的成员 “BaseClass.BaseMethod() '通过'BaseClass'类型的 修饰符;在 预选赛必须 类型的“DerivedClass”(或从中获得的)

有人能解释这种现象?这里发生了根本性的错误!

回答

15

埃里克利珀特只是blogged on this very topic

它的基本要点是确保一个类可以“信任”受保护方法的调用者。在这方面,共享一个公共基类的类(即使该公共基类定义了受保护的方法)本质上是陌生的。

埃里克的例子是基于银行申请的想法。而不是重建他的榜样,我就吐出在这里:

// 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,这使您处于信任圈之外。编译器不会分析所有的分配调用(或潜在的分配调用)以确定它是否“安全”。

+0

Thanks Adam :)这真的很有帮助。 – DotNetGuy 2010-01-21 17:19:16

+0

@DotNetGuy:谢谢;如果这回答您的问题,请记住将其标记为您接受的答案,以便其他人可以更轻松地找到答案。 – 2010-01-21 17:36:37

2

从C#规格:

当一个受保护的实例成员 的 在声明它的类的程序文本之外访问,并 当一个受保护的内部实例 件外的访问程序 宣布的程序文本为 ,需要访问 通过发生访问 的派生类类型的实例发生。

MSDN链接here

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 
    } 
}