13

为什么 ReSharper 在下面的示例中建议“设置”的只读字段?

如果我理解正确,如果仅在构造函数中更改此字段,则应使用readonly修饰符,但在我的示例中,我也在同一个类的另一个方法中更改它。

我错过了什么?

public partial class OptionsForm : Form
{
    private Settings settings;

    public OptionsForm(Settings s)
    {
        settings = s;
    }

    private void SaveData()
    {
        settings.ProjectName = TextBoxProject.Text;
    }
}
4

7 回答 7

27

当引用类型声明为只读时,指针是不可变的,但它指向的对象不可变。这意味着:

  • 可以初始化引用类型数据成员以指向类的实例,但是一旦完成,就不可能使其指向构造函数之外的类的另一个实例
  • readonly 修饰符对 readonly 数据成员指向的对象没有影响。

阅读有关此的详细文章

将 C# 类数据成员标记为只读时,它是只读的

于 2009-10-14T11:57:55.210 回答
5

请记住,编码标准和设计模式的主要原因是让人们更容易理解您的代码。

通过将字段标记为“只读”,您是在告诉类的读者他们不需要考虑字段的值是如何更改的。

但是,由于只读字段指向的对象可以更改其状态,因此将字段标记为只读有时可能会产生误导。所以想想天气,它可以帮助你的代码的读者(例如一个人)理解你的设计。

如果字段指向的对象中的值在对象生命周期内发生变化,那么我认为不应将字段标记为只读。(例如,指向的对象应该表现得好像在您的班级的承包商被调用时它是不可变的)

(但是也有一些例外,例如,即使记录器确实改变了日志文件的状态,也可以使用只读字段指向记录器。)

于 2009-10-14T12:42:14.170 回答
2

ReSharper 建议将“设置”设为只读:

readonly private Settings settings;

public OptionsForm(Settings s)
{
    settings = s;
}

因为,在扫描您的代码时,它会得出结论,您的“设置”字段仅出现在同一个类的构造函数中。

但是,如果您要在此类中提供修改“设置”的部分类或其他代码,则不再建议它是只读的。

一旦标记为只读,编译器就会将该字段的各种误用标记为警告,例如:

The left-hand side of an assignment must be an l-value

这与您尝试将值分配给常量时遇到的错误相同。

refout参数修饰符的使用也受到限制。

按照 ReSharpers 的建议,如果您尝试滥用初始化后您确实不打算更改的字段,编译器会警告您。

于 2011-12-11T17:33:05.157 回答
0

您没有在构造函数之外更改设置,对象与 SaveData 中的对象相同。对象属性可能会发生变化,但对象引用不会发生变化,因此从 Resharper 的角度来看,这似乎是有意义的。

于 2009-10-14T11:51:43.040 回答
0

SaveData() 方法不会更改设置变量,它会更改其属性之一。设置的内容(它所指的)只在构造函数中设置。

于 2009-10-14T11:53:14.597 回答
0

实际上,您是对的,而 Resharper 是错误的。仅当字段整体不可变时,才应将字段标记为只读。在您的示例中,如果您将其设为只读并启用 Microsoft 的代码分析,它将警告您设置具有可变属性。

于 2009-10-14T12:58:09.100 回答
0

这似乎有点奇怪,我无法想象 Eric Lippert 等人没有考虑一个明显的事实,即使引用不可变不会使引用不可变指向的实例,尽管提到的代码分析规则确实如此支持以上观点(http://msdn.microsoft.com/en-us/library/ms182302(v=VS.100).aspx)。

它仍然没有任何意义。如果可变实例不应该是只读的,那么在我看来,它应该是一个编译时错误,否则似乎毫无意义。

我可以看到使引用不可变的用途,而不是它指向的实例。

于 2011-04-11T14:29:27.137 回答