我一直试图绕过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的回答here和here,我知道持有对象引用的字段(在本例中为SomeStringBuilder)是readonly而不是对象本身(由{{1创建) }})
所以以这个例子为例,一旦该字段引用它,我将如何更改对象本身?我喜欢Eric Lippert's example如何更改readonly数组,并希望看到类似于任何其他可变引用类型的内容
答案 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分配给该字段(当它们属于同一类型时)之间确实没有功能差异,但是当字段中只有一个是有效的是只读的,但是因为你可以有效地改变字段所代表的值的价值,因为它已经说明并非真正只读了