不可变的只读参考类型& FXCop违规:不要声明只读可变引用类型

时间:2010-02-16 16:25:38

标签: c# string fxcop immutability readonly

我一直试图绕过FXCop违规行为“DoNotDeclareReadOnlyMutableReferenceTypes”

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

来自MSDN的代码会导致此违规行为:

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

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

从Jon的回答herehere,我知道持有对象引用的字段(在本例中为SomeStringBuilder)是readonly而不是对象本身(由{{1创建) }})

所以以这个例子为例,一旦该字段引用它,我将如何更改对象本身?我喜欢Eric Lippert's example如何更改readonly数组,并希望看到类似于任何其他可变引用类型的内容

5 个答案:

答案 0 :(得分:6)

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");
        }
    }
}

答案 1 :(得分:3)

由于MutableReferenceTypes类出现在问题中,因此SomeStringBuilder字段是私有的,因此无法从任何外部调用者实际改变它。

然而,该类本身可能会改变该字段。它目前没有,但它可以在以后的迭代中。

以下是一个示例方法:

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

调用Mutate方法会改变类,因为SomeStringBuilder现在已经改变了。

不可变性不仅仅是关于代码的当前版本,还包括保护自己免受未来错误的影响。并非所有类都需要是不可变的,但如果您选择创建不可变类型,则保持一致是最安全的。

答案 2 :(得分:0)

.Net有一个允许的不可变引用类型列表,StringBuilder不是其中之一。

抱怨是你正在构建的东西不是不可变的,虽然静态构造函数被调用一次并且类被初始化一次,所有这些都保持不变,其余的是可变的。一个线程可以调用.Append(),然后调用另一个...你会看到字符串构建器本身如何变异而不是真正的readonly,因为它不断地改变状态/变异。

声明它readonly实际上是一个误称,因为那里引用的对象本身就在不断变化。

答案 3 :(得分:0)

您无法更改引用,但对(可变)对象的任何调用都会更改其状态。

因此,由于SomeStringBuilder(在本例中)本身是可变的,因此其内容可能会发生变化,这可能会误导该类用户,因为它实际上并不是“只读”。

基本上,readonly不以任何方式保证对象不会改变,它只是说引用不会改变。

答案 4 :(得分:0)

您不会更改对象的值。这就是规则的要点。声明为readonly的任何字段都应该是readonly。具有只读可变参考是矛盾的。如果你可以改变字段“指向”的值,那么它不再是真正的只读。将某个对象A的所有成员的值分配给某个字段表示的某个对象B或者只是将A分配给该字段(当它们属于同一类型时)之间确实没有功能差异,但是当字段中只有一个是有效的是只读的,但是因为你可以有效地改变字段所代表的值的价值,因为它已经说明并非真正只读了

相关问题