【问题标题】:Is there a difference between private const and private readonly variables in C#?C# 中的私有 const 和私有只读变量之间有区别吗?
【发布时间】:2010-09-29 11:18:15
【问题描述】:

在 C# 中使用 private const 变量或 private static readonly 变量是否有区别(除了必须为 const 分配编译时表达式)?

由于它们都是私有的,因此没有与其他库的链接。那么它会有什么不同吗?例如,它可以产生性能差异吗?实习字符串?有没有类似的?

【问题讨论】:

    标签: c# constants readonly


    【解决方案1】:

    C#.Net 中 const 和 readonly 字段之间存在显着差异

    const默认是静态的,需要用常量值初始化,以后不能修改。构造函数中也不允许更改值。它不能用于所有数据类型。 对于前日期时间。它不能与 DateTime 数据类型一起使用。

    public const DateTime dt = DateTime.Today;  //throws compilation error
    public const string Name = string.Empty;    //throws compilation error
    public readonly string Name = string.Empty; //No error, legal
    

    readonly 可以声明为静态,但不是必需的。声明时无需初始化。可以使用构造函数分配或更改其值。因此,它在用作实例类成员时具有优势。两个不同的实例化可能具有不同的只读字段值。 对于前 -

    class A
    {
        public readonly int Id;
    
        public A(int i)
        {
            Id = i;
        }
    }
    

    然后可以使用即时特定值初始化只读字段,如下所示:

    A objOne = new A(5);
    A objTwo = new A(10);
    

    这里,实例 objOne 的只读字段值为 5,而 objTwo 的值为 10。使用 const 是不可能的。

    【讨论】:

      【解决方案2】:

      不同之处在于静态只读字段的值是在运行时设置的,因此可以由包含类修改,而 const 字段的值设置为编译时常量。

      在静态只读情况下,只允许包含类修改它

      在变量声明中(通过变量初始化器) 在静态构造函数中(实例构造函数,如果它不是静态的) 如果在 const 声明中不允许字段的类型,或者在编译时不知道该值,则通常使用 static readonly。

      也允许实例只读字段。

      请记住,对于引用类型,在两种情况下(静态和实例),只读修饰符只会阻止您为该字段分配新的引用。它特别不会使引用指向的对象不可变。

      class Program
      
      {
      
        public static readonly Test test = new Test();
      
        static void Main(string[] args)
      
        {
      
           test.Name = "Program";
      
           test = new Test(); // Error: A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)
      
        }
      
      }
      
      class Test
      
      {
      
         public string Name;
      
      }
      

      不同之处在于静态只读可以由包含类修改,但 const 永远不能修改,必须初始化为编译时常量。稍微扩展一下静态只读情况,包含类只能修改它:

      -- 在变量声明中(通过变量初始化器)。

      -- 在静态构造函数中(实例构造函数,如果它不是静态的)。


      C# .NET 中的常量关键字

      示例:public const string abc = “xyz”; 仅在声明时初始化。 值在编译时评估,不能在运行时更改。 尝试更改它会导致编译错误。 Const 已经是一种静态的了。 由于类和结构是在运行时使用 new 关键字初始化的,因此您不能为类或结构设置常量。但是,它必须是整数类型之一。 C# .NET 中的只读关键字

      示例:public readonly string abc; 可以在声明代码或构造函数代码中初始化。 在运行时评估值。 可以声明为静态或实例级属性。 只读字段可以通过在运行时使用 new 关键字来保存复杂对象。

      【讨论】:

        【解决方案3】:

        还有一件事。我在上面的 cmets 中没有看到这一点,尽管我可能错过了它。不能创建常量数组。

        private const int[] values = new int[] { 1, 2, 3 };
        

        但是您可以使用静态只读字段创建它。

        private static readonly int[] values = new int[] { 1, 2, 3 };
        

        因此,如果您需要一个数组常量,例如允许值的列表,并且枚举不合适,那么静态只读是唯一的方法。例如,如果数组是可以为空的整数,像这样:

        private static readonly int?[] values = new int?[] { null, 1, 2, 3 };
        

        不能那个用一个常数,可以吗?

        【讨论】:

          【解决方案4】:

          以下是 C# .NET const、readonly 和 static readonly 字段之间的区别(来自this article)。

          常量:

          • 默认静态
          • 必须有编译时值(即:你可以有“A”+“B”但不能有方法调用)
          • 可用于属性
          • 被复制到每个使用它们的程序集中(每个程序集都获得值的本地副本)
          • 可以在函数中声明

          只读实例字段:

          • 在创建实例时进行评估
          • 必须在构造函数退出时设置值

          静态只读字段:

          • 在代码执行命中类引用时进行评估(即:创建新实例或执行静态方法)
          • 必须在静态构造函数完成时评估值
          • 您真的不想将 ThreadStaticAttribute 放在这些上(因为静态构造函数将仅在一个线程中执行,并且会为其线程设置值;所有其他线程都将具有未初始化的此值)

          【讨论】:

            【解决方案5】:

            好吧,您可以在属性中使用 const,因为它们作为编译时存在。您无法预测静态只读变量的值,因为 .cctor 可以通过配置等对其进行初始化。

            在使用方面,常量被烧录到调用代码中。这意味着,如果您重新编译 library dll 以更改 public 常量,但不更改消费者,那么消费者仍将使用原始值。使用只读变量不会发生这种情况。反过来说,常量(非常非常快)更快,因为它只是加载值(而不是必须取消引用它)。

            重新实习;尽管您可以手动执行此操作,但这通常是文字的编译器/运行时功能;如果您通过文字初始化只读字段:

            someField = "abc";
            

            然后"abc" 将被拘留。如果您从配置中读取它,则不会。因为常量字符串必须是文字,所以它也会被实习,但访问方式不同:同样,从字段中读取是取消引用,而不是 ldstr。

            【讨论】:

            • 幸运的是,这对于 private 常量当然不是问题 - 但这是正常使用中最重要的区别。
            • 谢谢。我在另一个问题的答案中读到了对依赖程序集的影响。加载与取消引用很有趣,ldstr 也是如此。非常感谢!
            【解决方案6】:

            只读字段可以在声明或类的构造函数中初始化。因此,只读字段可以根据使用的构造函数具有不同的值。

            只读成员也可以用于运行时常量,如下例所示:

            public static readonly uint currentTicks = (uint)DateTime.Now.Ticks;
            

            只读字段不是隐式静态的,因此如果需要,静态关键字可以(必须)显式应用于只读字段。这对于隐式静态的 const 字段是不允许的。

            只读成员可以通过在初始化时使用new 关键字来保存复杂对象。

            【讨论】:

              【解决方案7】:

              确实,这两种类型在初始化后是无法改变的,但是它们之间还是有一些区别的:

              • 'const' 必须在声明它们的地方初始化(在编译时),而 'readonly' 可以在声明它的地方或在构造函数内部(ar 运行时)进行初始化。

              例如 const 可以用于这种情况:

              public class MathValues
              {
                public const double PI = 3.14159;
              }
              

              对于这种情况,readonly 会更好:

              public class Person
              {
                  public readonly DateTime birthDate;
              
                  public Person(DateTime birthDate)
                  {
                      this.birthDate = birthDate;
                  }
              }
              

              或

              public class Person
              {
                  public readonly DateTime birthDate = new DateTime(1986, 1, 24);
              }
              
              • 'const' 是静态的,因此它在该类的所有实例之间共享并且可以直接访问(如 MathValues.PI),而 'readonly' 不是静态的。因此,像 'static const' 这样的声明是非法的,因为 const 是静态的,但 'static readonly' 是合法的

              • 'const' 只能包含整数类型(sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool 或 string)、枚举或对 null 的引用(不是类或结构,因为它们是在运行时使用 'new' 关键字初始化的),而 'readonly' 可以保存复杂的类型、结构或类(通过在初始化时使用 new 关键字)但不能保存枚举

              【讨论】:

              • 谢谢,但我的问题更多是关于副作用而不是语言结构本身。
              【解决方案8】:

              关于常量需要注意的是它们实际上存储在您的可执行文件中,因此声明其中的很多会增加您的可执行文件大小。

              通常,这不是一个大问题,但我的一个朋友在公司工作,该公司强制执行“一切都必须是 const”规则,并设法显着增加了编译后的可执行文件大小。

              【讨论】:

              • 听起来像是 DailyWTF 的故事。
              • 好吧,没有 const,所有 DB 方法肯定更糟......我应该知道。
              • 相信我,这只是奇怪的编码指南的冰山一角。其他 gem 包括强制性 else 块,即使它们是空的,并且总是在内部调用公共属性。
              • @Stijn 我已经很久没有发布这个答案了,以至于我忘记了上下文。我想我可能指的是更大的可执行文件与资源文件,以及编译一个与另一个相比所花费的额外时间。
              【解决方案9】:

              正在使用中?并不真地。 Consts 在编译时评估,而 readonly 在运行时评估。您还可以在构造函数中为只读变量赋值。

              【讨论】:

              • 谢谢。但是绝对没有其他区别吗?也许 const 字符串会被拘留,但 readonly 不会? (我不知道;我只是在问。)
              • JIT 编译器将像 const 一样实习只读变量。
              猜你喜欢
              • 2013-06-22
              • 2011-05-25
              • 2021-04-18
              • 2019-11-04
              • 1970-01-01
              • 1970-01-01
              • 2021-05-11
              • 2014-10-23
              相关资源
              最近更新 更多