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

ram*_*ram 7 c# string fxcop readonly immutability

我一直试图围绕这个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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

从Jon 在这里这里的答案,我理解持有对象引用的字段(在本例中为SomeStringBuilder)是readonly而不是对象本身(由其创建new StringBuilder())

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

Bra*_*uff 6

readonly意味着您无法在构建后更改参考.

官方的FXCop立场是它建议只应声明不能修改的类型readonly.因此像a这样的东西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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ann 3

由于问题中出现了 MutableReferenceTypes 类,因此您无法真正从任何外部调用者处更改它,因为 SomeStringBuilder 字段是私有的。

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

这是一个示例方法:

public static void Mutate()
{
    SomeStringBuilder.AppendLine("Foo");
}
Run Code Online (Sandbox Code Playgroud)

调用 Mutate 方法将会改变该类,因为 SomeStringBuilder 现在已发生更改。

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

  • 只是一个小错误:该字段是**受保护的**,而不是私有的,因此它从外部“绝对”是可变的。我猜*这*就是 FXCop 所反对的。 (2认同)