在C#中将字段标记为“只读”有什么好处?

在C#中将字段标记为“只读”有什么好处?,c#,readonly,processing-efficiency,memory-efficient,C#,Readonly,Processing Efficiency,Memory Efficient,将成员变量声明为只读有什么好处?它只是为了防止有人在类的生命周期中更改其值,还是使用此关键字会提高速度或效率?使用readonly关键字将成员变量声明为常量,但允许在运行时计算值。这不同于使用const修饰符声明的常量,该修饰符必须在编译时设置其值。使用readonly可以在声明中或字段所属对象的构造函数中设置字段的值 如果您不想重新编译引用该常量的外部DLL(因为它在编译时被替换),也可以使用它。使用只读没有明显的性能优势,至少我从未在任何地方提到过。这只是为了完全按照你的建议去做,为了在初始

将成员变量声明为只读有什么好处?它只是为了防止有人在类的生命周期中更改其值,还是使用此关键字会提高速度或效率?

使用
readonly
关键字将成员变量声明为常量,但允许在运行时计算值。这不同于使用
const
修饰符声明的常量,该修饰符必须在编译时设置其值。使用
readonly
可以在声明中或字段所属对象的构造函数中设置字段的值


如果您不想重新编译引用该常量的外部DLL(因为它在编译时被替换),也可以使用它。

使用
只读
没有明显的性能优势,至少我从未在任何地方提到过。这只是为了完全按照你的建议去做,为了在初始化后防止修改

因此,它的好处在于它可以帮助您编写更健壮、更可读的代码。当您在团队中工作或进行维护时,这样做的真正好处就来了。将某事物声明为
只读
类似于在代码中为该变量的使用订立契约。将其视为以与其他关键字相同的方式添加文档,如
internal
private
,您的意思是“初始化后不应修改此变量”,而且您正在强制执行它


因此,如果您创建一个类并通过设计将一些成员变量标记为只读,那么您就可以防止您自己或其他团队成员在以后扩展或修改您的类时出错。在我看来,这是一个值得拥有的好处(正如doofledorfer在评论中提到的那样,以牺牲额外的语言复杂性为代价)。

我认为使用只读字段不会带来任何性能提升。这只是一个检查,以确保一旦对象完全构造,该字段就不能指向新值

但是,“readonly”与其他类型的只读语义非常不同,因为它是由CLR在运行时强制执行的。readonly关键字编译为.initonly,可由CLR验证

这个关键字的真正优点是生成不可变的数据结构。根据定义,不可变的数据结构一旦构建就无法更改。这使得在运行时对结构的行为进行推理变得非常容易。例如,将不可变的结构传递给代码的另一个随机部分是没有危险的。他们无法改变它,因此您可以根据该结构可靠地编程


这里有一个关于不变性的好处的好条目:

用非常实际的术语来说:

如果在dll a中使用常量,且dll B引用该常量,则该常量的值将编译为dll B。如果使用该常量的新值重新部署dll a,则dll B仍将使用原始值


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

请记住,readonly应用于值本身,因此如果使用引用类型,readonly将保护引用不被更改。实例的状态不受readonly保护

使用私有只读数组时要小心。如果将它们作为对象公开给客户机(您可以像我一样为COM互操作这样做),客户机可以操纵数组值。将数组作为对象返回时,请使用Clone()方法。

编译器可能会根据readonly关键字的存在进行性能优化

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

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


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

不要忘记有一种解决方法,可以在使用
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
}

这里进一步讨论:

WPF可以带来性能优势,因为它消除了对昂贵的依赖性属性的需要。这对于集合特别有用

使用只读标记的另一个有趣的部分是保护字段不在singleton中初始化

例如,在源代码中:

公共密封类单例
{
私有静态只读惰性=
新的懒惰(()=>newsingleton());
公共静态单例实例{get{return lazy.Value;}}
私人单身人士()
{
}
}

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

如果您有一个预定义的或预先计算的值需要在整个程序中保持不变,那么您应该使用常量,但是如果您有一个值需要在运行时提供,但一旦分配,在整个程序中应该保持不变,那么您应该使用readonly。例如,如果必须指定程序开始时间或
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()
    {
    }
}
using System;

class MainClass {
    public static void Main (string[] args) {

        Console.WriteLine(new Test().c);
        Console.WriteLine(new Test("Constructor").c);
        Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
        // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
        // variable initializer)
    }


    public class Test {
        public readonly string c = "Hello World";
        public Test() {

        }

        public Test(string val) {
          c = val;
        }

        public string ChangeC() {
            c = "Method";
            return c ;
        }
    }
}
public int Foo { get; }  // a readonly property
public readonly int Foo; // a readonly field