将成员变量声明为只读有哪些好处?它只是为了防止在类的生命周期中有人更改它的值,还是使用这个关键字会导致任何速度或效率的改进?


当前回答

令人惊讶的是,只读实际上会导致代码变慢,正如Jon Skeet在测试他的Noda Time库时发现的那样。在本例中,一个在20秒内运行的测试在删除readonly后只花了4秒。

https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/

其他回答

请记住,readonly只应用于值本身,所以如果您使用引用类型,readonly只保护引用不被更改。实例的状态不受只读保护。

使用只读标记的另一个有趣的部分是在单例中防止字段初始化。

例如,在csharpdepth的代码中:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

readonly在保护字段单例不被初始化两次方面起着很小的作用。另一个细节是,对于上述场景,您不能使用const,因为const强制在编译时创建,而单例在运行时创建。

不要忘记有一种变通方法,可以使用out参数在任何构造函数之外设置只读字段。

有点乱,但是:

private readonly int _someNumber;
private readonly string _someText;

public MyClass(int someNumber) : this(data, null)
{ }

public MyClass(int someNumber, string someText)
{
    Initialise(out _someNumber, someNumber, out _someText, someText);
}

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
    //some logic
}

进一步讨论请访问:http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx

用非常实际的术语来说:

如果在dll a中使用const,而dll B引用该const,则该const的值将被编译到dll B中。如果您使用该const的新值重新部署dll a, dll B将仍然使用原始值。

如果在dll a和dll B引用中使用该readonly,则运行时将始终查找该readonly。这意味着如果您使用该只读的新值重新部署dll A, dll B将使用该新值。

有一种可能的情况是,编译器可以基于readonly关键字的存在进行性能优化。

这仅适用于只读字段也标记为静态的情况。在这种情况下,JIT编译器可以假设这个静态字段永远不会改变。JIT编译器在编译类的方法时可以考虑到这一点。

一个典型的例子:你的类可以有一个静态只读的IsDebugLoggingEnabled字段,在构造函数中初始化(例如基于配置文件)。一旦实际的方法被jit编译,当调试日志未启用时,编译器可能会省略代码的整个部分。

我没有检查这个优化是否在当前版本的JIT编译器中实际实现,所以这只是推测。