2010-02-16 29 views
7

我一直在試圖總結我的頭圍繞此的FxCop侵犯「DoNotDeclareReadOnlyMutableReferenceTypes」不可變的只讀引用類型和FxCop的違規:不申報只讀可變引用類型

MSDN:從MSDN http://msdn.microsoft.com/en-us/library/ms182302%28VS.80%29.aspx

代碼這將導致此衝突:

namespace SecurityLibrary 
{ 
    public class MutableReferenceTypes 
    { 
     static protected readonly StringBuilder SomeStringBuilder; 

     static MutableReferenceTypes() 
     { 
      SomeStringBuilder = new StringBuilder(); 
     } 
    } 
} 

喬恩的回答herehere,據我所知,該領域保持參照對象(在這種情況下, SomeStringBuilder)是隻讀的,而不是對象本身(它由new StringBuilder()創建)

因此,考慮這個例子,一旦字段有引用它,我將如何更改對象本身?我喜歡Eric Lippert's example如何更改只讀數組,並希望看到類似的任何其他可變參考類型

回答

3

由於MutableReferenceTypes類在問題中提供,因此您無法從任何外部調用者真正改變它,因爲SomeStringBuilder字段是私人的。

但是,該類本身可能會改變該字段。它目前不是,但它可能在以後的迭代中。

下面是一個例子方法:

public static void Mutate() 
{ 
    SomeStringBuilder.AppendLine("Foo"); 
} 

調用發生變異的方法,因爲SomeStringBuilder現在已經改變會產生變異的類。

不變性不僅是關於您的代碼的當前化身,而且還關於保護自己免受未來錯誤的影響。並不是所有的類都必須是不可變的,但如果選擇創建不可變類型,則最安全的做法是保持一致。

+0

不錯。太棒了。完善。 – ram 2010-02-16 16:48:22

+2

只是一個小小的錯誤:該領域是**保護**,而不是私人的,因此它從外部是絕對*可變的。我猜這個*是FXCop反對的。 – 2010-02-16 18:57:11

+0

@Konrad魯道夫:很好!我只看了第一個關鍵字並注意到它不是訪問修飾符,因此必須默認爲默認(原文如此)。我沒有注意到關鍵字已被切換。 – 2010-02-16 19:29:42

0

.Net有一個不可變參考類型列表允許在這裏,StringBuilder不是其中之一。

抱怨是,你正在構建的是不可改變的,雖然靜態構造函數被調用一次,並且類被初始化一次,這一切都保持不變,其餘都是可變的。一個線程可能會調用.Append(),然後另一個線程...您會看到字符串生成器本身是如何變異的,並不是真的readonly,因爲它會不斷改變狀態/變化。

聲明它readonly確實是一個用詞不當,因爲在那裏引用的對象本身在不斷變化。

+1

還應該如何區分將始終指向同一個對象的引用類型字段和可能在包含對象的生命週期中指向不同對象的引用類型字段?不明白參考類型的人可能會感到困惑,但是除非或者直到他學會了解參考類型時,這樣的人才會對許多事情感到困惑。 – supercat 2012-11-03 03:50:24

0

您不能更改引用,但(可變)對象上的任何調用都會更改其狀態。

因此,由於SomeStringBuilder(本例中)本身是可變的,所以它的內容可能會改變,這對於類的用戶可能會產生誤導,因爲它不是真正的「只讀」。

基本上,readonly不以任何方式保證對象的敵人沒有改變,它只是說,參考不會改變。

+1

引用不會改變的事實對於代碼的其他部分可能是至關重要的(例如,某些其他對象可能會獲取對StringBuilder的引用並希望能夠獲取其值);而一個人當然應該意識到被引用的對象可能會被突變,這並不意味着關於聲明引用本身不可變是沒有任何用處的。順便說一句,即使代表並不總是不變的;由結構增變器形成的代表會將結構框起來,並且盒裝結構將是可變的。 – supercat 2011-01-20 15:52:22

0

您不會更改對象的值。這是規則的要點。聲明爲只讀的字段應該是隻讀的。有隻讀的可變參考是一個矛盾。如果你可以改變字段「指向」的值,那麼它就不再是隻讀了。將某個對象A的所有成員的值賦值給某個字段所表示的某個對象B,或者簡單地將A賦值給該字段(當它們屬於同一類型時)之間確實沒有功能上的區別,但是隻有其中一個有效時被聲明爲只讀的,但由於您可以有效地改變字段的值,因此已經聲明不是真正只讀的

5

readonly表示您無法更改參考後構建。

FXCop的官方立場是,它建議只有不能修改的類型應該被聲明爲readonly。因此,像string這樣的東西是可以的,因爲對象的值不能被改變。但是,StringBuilder的值可以更改,但只允許在運行構造函數後將該字段分配給不同的StringBuilder實例或null

我不同意FXCop這個規則。只要有人明白這只是一個強制性的規定,參考文件可能不會在施工後發生變化,那麼就沒有混淆。

請注意,值類型通過readonly關鍵字不可變,但引用類型不是。

namespace SecurityLibrary 
{ 
    public class MutableReferenceTypes 
    { 
     static protected readonly StringBuilder SomeStringBuilder; 

     static MutableReferenceTypes() 
     { 
      // allowed 
      SomeStringBuilder = new StringBuilder(); 
     } 

     void Foo() 
     { 
      // not allowed 
      SomeStringBuilder = new StringBuilder(); 
     } 

     void Bar() 
     { 
      // allowed but FXCop doesn't like this 
      SomeStringBuilder.AppendLine("Bar"); 
     } 
    } 
} 
+0

代碼+1。在MSDN中鏈接你的代碼。如果您早些時候回答過問題,本來會標記爲答案。反正好! – ram 2010-02-16 18:17:02

+0

舊的答案,但仍然非常相關。代碼分析(就像現在這樣)仍然有一些愚蠢的規則(比如這個),假設編碼者是白癡。任何人只要懂一點就懂得「只讀」的意思。我在設置新項目時所做的第一件事是禁用大量CA規則,例如CA2104。 – 0b101010 2016-07-08 09:37:38

相關問題