代码之家  ›  专栏  ›  技术社区  ›  ram

不可变只读引用类型&fxcop冲突:不要声明只读可变引用类型

  •  7
  • ram  · 技术社区  · 15 年前

    我一直在试图回避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();
            }
        }
    }
    

    从乔恩的回答中 here here ,我理解包含对象引用的字段(在本例中是somestringbuilder)是只读的,而不是对象本身(由 new StringBuilder() )

    因此,在这个例子中,一旦字段引用了对象本身,我将如何更改它?我喜欢 Eric Lippert's example 说明如何更改只读数组,并希望看到与任何其他可变引用类型类似的内容

    5 回复  |  直到 15 年前
        1
  •  3
  •   Mark Seemann    15 年前

    由于mutablereferencetypes类出现在问题中,因此您不能真正从任何外部调用程序对其进行更改,因为somestringbuilder字段是私有的。

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

    下面是一个示例方法:

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

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

    不变性不仅关系到代码的当前体现,还关系到保护自己不受将来错误的影响。并非所有的类都需要是不可变的,但是如果您选择创建一个不可变的类型,那么保持一致是最安全的。

        2
  •  6
  •   Brandon Cuff    15 年前

    readonly 表示不能更改参考后期构造。

    fxcop的官方立场是,它建议只声明不能修改的类型 readonly . 所以有点像 string 可以,因为无法更改对象的值。但是 StringBuilder 无法更改,但使其只读只会阻止您将字段分配给 字符串拼接 实例或 null 在构造函数运行之后。

    我不同意fxcop的这条规则。只要一个人明白这只是一种执行,即引用可能不会改变后构造,那么就没有混淆。

    请注意,值类型由 只读 关键字,但引用类型不是。

    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");
            }
        }
    }
    
        3
  •  0
  •   Nick Craver    15 年前

    .NET具有此处允许的不可变引用类型列表, StringBuilder 不是他们中的一个。

    抱怨的是,您正在构造的不是不可变的,尽管静态构造函数被调用一次,类被初始化一次,但这是保持不变的,其余的都是可变的。一个线程可以调用 .Append() ,然后另一个……你看到了字符串生成器本身是如何变化的,而不是真正的 readonly 因为它不断地改变状态/变异。

    声明它 只读 是一个误称,因为引用的对象本身是不断变化的。

        4
  •  0
  •   Lucero    15 年前

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

    因此,由于 SomeStringBuilder (在本例中)本身是可变的,其内容可能会更改,这可能会误导类的用户,因为它因此不是真正的“只读”。

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

        5
  •  0
  •   Rune FS    15 年前

    您不会更改对象的值。这就是规则的要点。声明为readonly的任何字段都应为infact,readonly。具有只读可变引用是一种矛盾修饰。如果你能改变字段“指向”的值,那么它就不再是只读的了。将某个对象A的所有成员的值赋给由字段表示的某个对象B,或者简单地将A赋给该字段(当它们属于同一类型时),这两者之间实际上没有任何功能上的区别,但是当字段声明为只读时,只有一个有效,但是因为您可以有效地改变要表示的值由字段指定,它是已声明的,不是真正只读的