2011-12-20 16 views
19

如果我改變私人公共setter方法的公共訪問修飾符,是導致引用它的其它組件的任何重大更改?修改公共屬性的訪問修飾符是一個突破性變化嗎?

+0

不,那些其他程序集以前從未能夠使用該屬性。 – 2011-12-20 19:07:15

+0

@Hans,屬性的獲取者是公開的,所以其他程序集可以使用它。 – mkus 2011-12-20 19:09:30

+0

嗯,你沒有改變吸氣劑嗎? JIT編譯器對更改的屬性聲明沒有任何問題。 – 2011-12-20 19:11:27

回答

31

UPDATEThis question was the topic of my blog in January 2012。感謝您的好問題!


我認爲是「重大更改」你的意思是「當我重新編譯依賴此彙編代碼,是否用來編譯代碼仍然編譯?」

嚴格地說,是的,通過這個定義,將一個曾經是私人的財產創造者公之於衆是一個突破性的改變。假設你有這樣的代碼:

// Assembly Alpha 
public class Charlie 
{ 
    public int P { get; private set; } 
} 
public class Delta 
{ 
    public int P { get; set; } 
} 

然後在引用阿爾法另一個組件:

// Assembly Echo 
class Foxtrot 
{ 
    static void M(Action<Charlie> f) {} 
    static void M(Action<Delta> f) {} 
    static void Golf() 
    { 
     M(y=>{y.P = 123;}); 
    } 
} 

編譯裝配回聲。 Foxtrot類有一個方法Golf,它可以在M上重載分辨率。M有兩個重載;一個對查理採取行動,另一個對達美行動採取行動。如果lambda參數y是Charlie類型,那麼lambda體將產生可訪問性錯誤,因此M的重載不是適用的候選。重載解析選擇第二次重載並編譯成功。

現在你改變程序集Alpha,以便Charlie.P的setter是公開的。你重新編譯Echo。現在你得到了一個重載分辨率的錯誤,因爲兩個M的重載都是同樣有效的,並且都不比其他重載更好。由於Alpha中的更改,回聲編譯失敗。你對Alpha的改變是一個突破性的改變。

問題不在於「這是一個突破性的改變嗎?」很明顯,幾乎所有的變化都是某種突破性的變化。問題應該是突破性改變是否會在實際中破壞任何人,如果是這樣,那麼與新特性的好處相比,修復破裂的成本是多少?

+2

布拉沃發生了什麼事? – kvb 2011-12-20 20:00:55

+20

@kvb:我曾經給一家航空公司打過電話改變預訂,而且電話中有用的女士說:「如果有問題,這裏是您的確認號碼:153ADN6,即1-5-3-Alpha-Dog-November- 6「,我說:」謝謝,但不是達美D的國際廣播代碼字?「她說:「*我們不會在這家航空公司說這句話!*」我告訴你,在一家航空公司打電話給一個*人*是很難的;找一個懂得引導國際廣播字母的聰明而有趣的人確實很稀罕。 – 2011-12-20 22:14:23

+2

如果它實際上是您打電話給達美航空公司的話,那會更有趣。 – 2011-12-21 00:00:31

5

這取決於你想如何嚴格約爲「重大更改」。

一個定義是:它是否會破壞引用代碼的構建或執行。

另一種是,可以在其他代碼確定您所做的更改。

通過的第一個定義,這不是一個重大更改。通過第二個定義,這是一個突破性的變化。

+1

[Eric的回答](http://stackoverflow.com/a/8581029)和[Jeffrey的回答](http://stackoverflow.com/a/8581019)提供了會破壞編譯的邊緣情況。 – Brian 2011-12-20 19:50:55

0

我不認爲,但你應該知道什麼是使這個setter私人背後的智慧。訪問修飾符對庫消費者和封裝很重要。

3

它可能是,如果其他程序集使用反射來測試setter的存在。

但早期綁定代碼不會打破。

要考慮的另一件事是,這是否是語義的變化。如果只是施工過程中的屬性以前設置,並且在任何時候,現在可以修改的,那肯定可以打破消費者誰緩存值,用它作爲字典鍵等

2

由於屬性的可見性增加現在靜態鏈接的程序集和靜態引用不應該有任何問題 - 那些程序集直到現在纔將您的屬性視爲只讀,並且它們繼續這樣做。

可能潛在地出現在這裏唯一的問題是,如果一些組件使用反射來獲取關於你的屬性信息並執行一些動作。

例如,如果這是您使用數據綁定來顯示您的數據在一些控制,如GridViewListView(獨立於實際的框架),這也許是因爲這是一個業務對象的屬性屬性現在將被識別爲「可更新」,並且用戶可能會改變您(和其他一些程序集)認爲迄今爲止不變的某些值。

17

這是一個重大更改,因爲它可能會導致現有的代碼不再編譯。

一些語言不允許您覆蓋屬性沒有覆蓋所有可見的存取。 VB是這樣一種語言。

假設你有下面的C#類:

namespace TestLibrary 
    public class A { 
     public virtual int X { 
      get { return 0; } 
      private set { Console.WriteLine("A.set_X called."); } 
     } 
    } 
} 

在VB項目中引用你的圖書館,你有一個類定義:

Class B : Inherits TestLibrary.A 
    Public Overrides ReadOnly Property X As Integer 
     Get 
      Return MyBase.X 
     End Get 
    End Property 
End Class 

通知的ReadOnly修改的財產。這在VB中是必需的,因爲你只是定義了getter。如果你離開它,你就會得到一個編譯時錯誤:

Property without a 'ReadOnly' or 'WriteOnly' specifier must provide both a 'Get' and a 'Set'.

現在,請從二傳手的private修飾符在C#類:

namespace TestLibrary 
    public class A { 
     public virtual int X { 
      get { return 0; } 
      set { Console.WriteLine("A.set_X called."); } 
     } 
    } 
} 

現在你會得到一個編譯時在您的VB代碼中出現錯誤:

'Public Overrides ReadOnly Property X As Integer' cannot override 'Public Overridable Property X As Integer' because they differ by 'ReadOnly' or 'WriteOnly'.

引用您的庫的代碼在進行更改後無法編譯,因此這是一個重大更改。

+5

好的!語言間休息是一些最棘手的問題。 – 2011-12-21 16:00:06

+0

我真的很討厭實現屬性的方式。淨;我有三種屬性的真正優勢,其中一種包括兩種方法,而不僅僅是屬性獲取器和設置器,它們是具有某些屬性的方法,表明爲了語法的目的,調試顯示,序列化等等。應該視爲屬性?如果程序可以接受類型爲「Property 」的參數,我可以看到將吸氣劑和吸氣劑作爲單一實體綁定在一起的一些真正的好處,但事實並非如此。那麼有什麼好處? – supercat 2012-01-10 23:28:32

+0

@supercat這正是.NET中屬性的工作原理:IL從不調用屬性,只調用方法。屬性僅存在於元數據中。 getter和setter方法不容易獲取的事實是語言設計的問題:它們是公共方法,但由於它們具有'SpecialName'屬性而被大多數語言隱藏。爲什麼C#顯式阻止你調用這些方法,我不知道。 – 2012-01-11 02:15:27