C#中私有const和私有只读变量之间有区别吗?

Is there a difference between private const and private readonly variables in C#?

在C中有一个private const变量或一个private static readonly变量有区别吗(除了必须给const分配编译时表达式之外)?

因为它们都是私有的,所以没有与其他图书馆的链接。那会有什么不同吗?例如,它能改变性能吗?实习弦?有类似的吗?


好吧,您可以在属性中使用const,因为它们作为编译时存在。您不能预测静态只读变量的值,因为.cctor可以从配置等初始化它。

在用法上,常量被烧掉到调用代码中。这意味着,如果重新编译库dll以更改公共常量,但不更改使用者,则使用者仍将使用原始值。如果使用只读变量,则不会发生这种情况。反过来,常数(非常,非常轻微)更快,因为它只加载值(而不必取消引用)。

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

1
someField ="abc";

然后,"abc"将被拘留。如果你从config中读取它,它就不会。因为常量字符串必须是一个文本,所以它也将被实习生,但访问方式不同:同样,从字段读取是一个去引用,而不是一个ldstr


实际上,这两种类型在初始化后无法更改,但它们之间存在一些差异:

  • "const"必须在声明的位置初始化(在编译时),而"readonly"可以在声明的位置或在构造函数(ar运行时)内初始化。

例如,在这种情况下可以使用const:

1
2
3
4
public class MathValues
{
  public const double PI = 3.14159;
}

对于这种情况,只读更好:

1
2
3
4
5
6
7
8
9
public class Person
{
    public readonly DateTime birthDate;

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

1
2
3
4
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)、枚举或对空值的引用(不是类或结构,因为它们是在运行时用"new"关键字初始化的),而"readonly"可以保存复杂类型、结构或类(通过使用n初始化时的ew关键字),但不能保存枚举


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

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


这里是C.NET常量、只读字段和静态只读字段之间的区别(来自本文)。

常数:

  • 默认为静态
  • 必须有编译时间值(即:可以有"a"+"b",但不能有方法调用)
  • 可用于属性
  • 复制到使用它们的每个程序集中(每个程序集都获取值的本地副本)
  • 无法在函数中声明

只读实例字段:

  • 在创建实例时计算
  • 必须在构造函数退出时设置值

静态只读字段:

  • 当代码执行命中类引用(即创建新实例或执行静态方法)时进行评估。
  • 静态构造函数完成时必须已计算出值
  • 您确实不想将threadstaticattribute放在这些线程上(因为静态构造函数只在一个线程中执行,它将为其线程设置值;所有其他线程都将具有未初始化的该值)

在C.NET中,const和readonly字段之间存在显著差异。

常量在默认情况下是静态的,需要用常量值初始化,以后不能修改。构造函数中也不允许更改值。它不能与所有数据类型一起使用。对于ex-datetime。它不能与datetime数据类型一起使用。

1
2
3
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

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

1
2
3
4
5
6
7
8
9
class A
{
    public readonly int Id;

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

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

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

这里,实例objone的readonly字段值为5,objtwo的readonly字段值为10。使用const是不可能的。


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

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

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

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

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

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

不能用常数来做吗?


在使用中?不是真的。常量在编译时计算,而只读则在运行时计算。也可以在构造函数中为只读变量赋值。


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

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

在变量声明中(通过变量初始值设定项)在静态构造函数中(实例构造函数,如果不是静态的话)如果常量声明中不允许字段类型,或者编译时不知道该值,则通常使用静态只读。

也允许使用实例只读字段。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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中的const关键字

示例:public const string abc ="xyz";仅在声明处初始化。值在编译时计算,不能在运行时更改。尝试更改它将导致编译错误。常量已经是静态的了。由于类和结构是在运行时用new关键字初始化的,因此不能将常量设置为类或结构。但是,它必须是积分类型之一。C.NET中的只读关键字

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


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

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

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

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

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