2012-01-29 54 views
2

在C#中,嵌套類可以訪問包含類的私有成員。爲什麼我無法重寫嵌套類中的私有成員?

爲什麼我不能重寫這些成員?爲什麼編譯器錯誤?

private abstract class InheritanceTest 
    { 
     public virtual object Property 
     { 
      get { return null; } 
      private set { } 
     } 

     public class Child : InheritanceTest 
     { 
      public override object Property 
      { 
       get { return null; } 
       private set { base.Property = null; } // the base.Property = null statement here is just to show that there isn't an error message for accesing a parent private member. 
      } 
     } 
    } 

唯一的錯誤消息我得到的是:

'Program.InheritanceTest.Child.Property.set':不能覆蓋繼承成員 'Program.InheritanceTest.Property.set',因爲它不是標記爲虛擬,抽象或覆蓋

編譯器明顯出錯,因爲整個屬性被標記爲虛擬。 get方法可以覆蓋繼承的成員。

這是C#規範的一部分,只有錯誤消息是錯誤的?或者應該允許嗎?

我錯過了什麼規範? (或者是編譯器不見了?)

+1

的可能重複[爲什麼在C#中的非法私人虛擬方法?(http://stackoverflow.com/questions/3082310/why-are-private-virtual-方法非法在C) – McKay 2012-01-29 05:43:23

+0

我已投票結束這個問題作爲重複。我會鼓勵其他人也這樣做。 – McKay 2012-07-17 20:31:14

回答

3

有沒有這樣的事情virtual private。因此,由外部類定義的set訪問者不是virtual,因此您無法覆蓋它。

對於方法中,所述說明書明確禁止private virtual(該C#4規範的第10.6節):

如果聲明包括private改性劑,則聲明不包含任何以下修飾符:virtualoverrideabstract

至於特性(第10.7節):

屬性聲明都受到相同的規則方法聲明(第10.6節)中有關改性劑的有效組合。

說明書的唯一部分,這似乎是有關virtual屬性,其中所述存取器中的一個是private是(§10.7.5):

virtual屬性聲明指定了存取器該屬性是虛擬的。 virtual修飾符適用於讀寫屬性的兩個訪問器 - 讀寫屬性只有一個訪問者不可能是虛擬的。

這似乎與實際發生的情況相矛盾:只有非private訪問器變爲虛擬。除非我錯過了一些東西,否則我認爲這是文檔或編譯器中的錯誤。我已經創建了一個關於這個的Connect bug,讓我們看看微軟有什麼要說的。

有關private virtual方法的更多信息,請參閱this answer from Eric Lippert

+0

+1對規範的引用,但我認爲這一行文檔是正確的。 '虛擬'省略的地方在非讀寫屬性的情況下(不管是隻讀的還是隻寫的,其只有1個虛擬成員)。請記住,如果get或set被標記爲'private',那麼它不再是'virtual',並且屬性不再是「讀寫」,因此不符合該規範的那一行。 – CodingWithSpike 2012-01-29 15:51:20

+0

僅僅因爲其中一個訪問器具有不同的可訪問性,並不意味着該屬性不再是可讀寫的。或者至少我沒有在規範中找到任何可以這樣說的東西。 – svick 2012-01-29 20:48:16

+0

啊,是的,我明白你的意思,對不起,我從派生類的角度思考「只讀」和「只寫」,而不是基類本身。抱歉。在那種情況下,是的,我認爲你的觀點是錯的。 – CodingWithSpike 2012-01-30 01:46:44

1

顧名思義,private成員不可覆蓋。 如果您希望setter被覆蓋,您可以將其標記爲protected而不是private

private abstract class InheritanceTest 
    { 
     public virtual object Property 
     { 
      get { return null; } 
      protected set { } 
     } 

     public class Child : InheritanceTest 
     { 
      public override object Property 
      { 
       get { return null; } 
       protected set { base.Property = null; } 
      } 
     } 
    } 

爲了更具體地回答你的問題,以爲什麼

理解的是,當你的C#代碼被編譯成IL代碼,實際上最終是三樣東西1財產。

  1. Property屬性本身。
  2. 名爲get_Property()的方法是吸氣劑。
  3. 方法名稱set_Property()這是設置者。

在你的代碼,你告訴.NET說:「我希望有一個virtual的屬性,它然後訪問級別的getter和setter方法級聯。事實上,在IL代碼,性能不指定virtual在所有。

對於C#代碼:

public virtual object Property { get; set; } 

所生成的IL代碼是:

.property instance object Property() { ... } 

.method public hidebysig newslot specialname virtual 
    instance object get_Property() cil managed 
    { ... } 

.method public hidebysig newslot specialname virtual 
    instance object set_Property() cil managed 
    { ... } 

請注意,publicvirtual關鍵字既適用於getter方法,也適用於setter方法,但不適用於屬性本身。

現在,通過改變你的C#代碼:您希望您的getter和setter方法是虛擬

public virtual object Property { get; private set; } 

你告訴.NET ...但是,然後將它運行到private set,和訪問級別覆蓋publicvirtual訪問級別,用於setter方法。因此,生成的IL代碼變爲:

.property instance object Property() { ... } 

.method public hidebysig newslot specialname virtual 
    instance object get_Property() cil managed 
    { ... } 

.method private hidebysig newslot specialname 
    instance object set_Property() cil managed 
    { ... } 

注意,現在set_Property()private,並且不再virtual。在.NET中實際上不可能有一個private virtual,因爲它沒有意義......這就像試圖說「沒有其他類可以看到這個......但派生類可以重寫這個東西,他們可以'沒有看到或訪問「這是沒有意義的。派生類不能覆蓋他們甚至看不到的東西。

protected關鍵字在這種情況下是正確的替代品,因爲它告訴.NET「只有我自己和派生類可以看到或訪問它,並且派生類可以覆蓋此屬性。」

所以我猜這個「短」的答案會剛剛「因爲事情不能在.NET privatevirtual,所以編譯器需要你給它的更嚴格的訪問級別。

而且, IMO該錯誤消息是相當正確

「Program.InheritanceTest.Child.Property.set」:無法重寫繼承的成員「Program.InheritanceTest.Property.set」,因爲它未標記虛擬的,抽象的,或覆蓋

請注意,它說的是'Program.InheritanceTest.Property.set',所以最後的「.set」是指最終的set_Property()方法,而不是Property屬性。並且set_Property()方法僅標記爲private,因爲.NET編譯器看到該方法,並從該方法中刪除了virtual,原因如上所述。我想假設有一個編譯器警告或者說'虛擬'將被忽略'set''會有些意義。

希望更有意義......

+0

是的,我已經這樣做了,真正的問題是「爲什麼我必須?」和「爲什麼錯誤信息不太有用?」 – McKay 2012-01-29 05:41:53

+0

@McKay - 我擴大了我的答案,試圖解釋「爲什麼」。 – CodingWithSpike 2012-01-29 15:48:11

相關問題