2010-01-21 47 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 
    } 
}