C# CA2104 - 自动化代码分析不喜欢静态只读可变类型

4

I've got a code like this:

public abstract class Base
{
    // is going to be used in deriving classes
    // let's assume foo is threadsafe
    protected static readonly Foo StaticFoo = new Foo();
}

Visual Studio 2008的代码分析弹出以下消息:

CA2104:Microsoft.Security:从“Base.StaticFoo”中删除只读标记,或将该字段更改为不可变引用类型之一。如果引用类型“Foo”实际上是不可变的,则排除此消息。

我的设计本质上有缺陷吗?还是我可以在源代码中添加[SuppressMessage]

3个回答

8
问题在于它给人留下了错误的印象——它让人觉得这个值不能改变,实际上只是字段值不能改变,而不是对象本身。我认为代码分析过于谨慎了——有很多情况下你可能想要在只读字段中存储可变类型,特别是如果它是私有的,在静态初始化程序中初始化,然后在您的代码中从未被改变。
然而,当字段受保护时,衍生类滥用它的风险更大。个人而言,我喜欢所有字段都是私有的。另一方面,我不知道你的代码——也许你已经权衡了可能性,决定这样做是正确的。
如果Foo确实是线程安全的,除了字段是只读的这一事实之外,没有太多需要担心的了。我会为该行禁用警告,并添加一个注释以强调对象是可变的,尽管该字段是只读的。

有人能在这个答案中看到任何有用的东西,而在旧的两个答案中没有吗?如果没有,我会删除它。 - Jon Skeet
是的,你的回答很有帮助,请不要删除它。 - mafu
实际上,我经常在我修改的私有字段上使用readonly(但不是static)。我想要确保的唯一一件事情就是实例始终是相同的,并且我不会意外地在以后交换它。因此,我认为对于可变类型来说,readonly仍然是有用的。 - mmmmmmmm
它是有效的 - 你只需要确保每个人都理解 readonly 修饰符的限制即可。 - Jon Skeet
@Jon,你是否会认为私有字段作为一种默认做法应该标记为“readonly”,除非你知道该字段的值需要被重新赋值?换句话说,当涉及到标记私有字段为“readonly”时,如果该字段是可变的,你是否会犹豫? - devuxer
@DanM:这取决于我们讨论的是哪种类型,但是在可能的情况下,我基本上默认使用不可变性。 - Jon Skeet

3

Foo类型是不可变的吗?

如果不是,你是否打算仅使用此一个Foo对象,但需要能够更改其属性?如果是这种情况,那么警告只是在说readonly关键字具有误导性。没有编译错误-对该对象的引用是只读的,并且这就是您向编译器声明的内容。但是,您向其他开发人员声明的是StaticFoo是只读的,这意味着它永远不会更改。

所以,正如它所述,你有选择。要消除此警告,请删除readonly关键字或添加SuppressMessage属性。或者,查看代码设计。例如,实现Foo作为单例模式是否更合适?


1
警告告诉你,readonly修饰符仅适用于引用本身。如果Foo是引用类型,则除非确保Foo是不可变的,否则可能仍然可以修改Foo实例的状态。
另外,像这样的静态变量在单元测试代码时可能会导致各种问题,因此如果这对你很重要,你可能需要寻找其他方法来实现你想要做的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接