找回密码
 立即注册
首页 业界区 业界 C# 中 const 和 readonly 关键字的区别和用法 ...

C# 中 const 和 readonly 关键字的区别和用法

方方仪 12 小时前

前言

今天我们一起来讲讲 C# 中 const 和 readonly 关键字的区别和用法。
const 和 readonly 关键字区别

基本介绍


  • const(常量): 在C#中用于声明编译时常量,其值在编译时就必须确定,并且在程序生命周期内不可更改。
  • readonly(只读字段): 在C#中用于声明运行时常量,其值可以在声明时或构造函数中初始化,之后不可更改(可通过反射强制修改)。
const 和 readonly 异同点

对比维度constreadonly基础定义编译时常量,值在编译期确定运行时常量,值在运行时确定初始化时机必须在声明时初始化可在声明时或构造函数中初始化支持的数据类型仅支持基元类型(int, float, char, bool等)、string和null引用支持所有类型(包括自定义类和结构体)默认值要求必须显式初始化不需要显示初始化,值类型默认零值,引用类型默认null性能表现零开销访问(直接编译到IL)微小访问开销(作为实例/静态字段分配内存)线程安全天然线程安全实例字段需注意可见性,静态字段线程安全反射修改无法通过反射修改可通过反射强制修改IL元数据标记literal 标记initonly 标记使用场景声明常量字段或本地常量,常量可以是数字、布尔值、字符串或 null 引用等声明依赖注入对象、配置值、运行时计算值等const 和 readonly 关键字使用

const 使用
  1.     public enum UserRole
  2.     {
  3.         Admin,
  4.         User,
  5.         Guest
  6.     }

  7.     public class ConstAndReadonlyExercise
  8.     {
  9.         // const 初始化
  10.         public const int MaxCount = 999;
  11.         public const UserRole CurrentUserRole = UserRole.Admin;
  12.     }
复制代码
编译后 IL 代码:

  • literal 关键字:标记为字面量,值直接嵌入调用处的 IL。
  1.   .field public static literal int32 MaxCount = int32(999) // 0x000003e7

  2.   .field public static literal valuetype 'HelloDotNetGuide.CSharp语法.UserRole' CurrentUserRole = int32(0) // 0x00000000
复制代码
readonly 使用
  1.  // readonly 初始化
  2.  public readonly string _applicationName = "HelloDotNetGuide";

  3.  public ConstAndReadonlyExercise()
  4.  {
  5.      _applicationName = "HelloDotNetGuide_V2";
  6.  }

  7.  // 懒汉式单例模式示例
  8.  private static ConstAndReadonlyExercise? _instance;
  9.  private static readonly object _lockObj = new object();

  10.  public static ConstAndReadonlyExercise Instance
  11.  {
  12.      get
  13.      {
  14.          if (_instance == null)
  15.          {
  16.              lock (_lockObj)
  17.              {
  18.                  _instance ??= new ConstAndReadonlyExercise();
  19.              }
  20.          }
  21.          return _instance;
  22.      }
  23.  }

  24.  /// <summary>
  25.  /// 反射修改 readonly 字段的值
  26.  /// </summary>
  27.  public static void UpdateApplicationNameValue()
  28.  {
  29.      var instance = new ConstAndReadonlyExercise();
  30.      Console.WriteLine($"初始值: {instance._applicationName}");
  31.      // 输出: 初始值: HelloDotNetGuide_V2

  32.      var field = instance.GetType().GetField("_applicationName");
  33.      field.SetValue(instance, "HelloDotNetGuide_V3");

  34.      Console.WriteLine($"修改后: {instance._applicationName}");
  35.      // 输出: 修改后: HelloDotNetGuide_V3
  36.  }
复制代码
编译后 IL 代码:

  • initonly 关键字:标志被 CLR 识别为仅构造函数可写约束。
  1.   .field public initonly string _applicationName

  2.   .field private static class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise' _instance
  3.     .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(unsigned int8)
  4.       = (01 00 02 00 00 ) // .....
  5.       // unsigned int8(2) // 0x02

  6.   .field private static initonly object _lockObj

  7.   .method public hidebysig specialname rtspecialname instance void
  8.     .ctor() cil managed
  9.   {
  10.     .maxstack 8

  11.     // [25 9 - 25 70]
  12.     IL_0000: ldarg.0      // this
  13.     IL_0001: ldstr        "HelloDotNetGuide"
  14.     IL_0006: stfld        string 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_applicationName

  15.     // [29 9 - 29 42]
  16.     IL_000b: ldarg.0      // this
  17.     IL_000c: call         instance void [System.Runtime]System.Object::.ctor()
  18.     IL_0011: nop

  19.     // [30 9 - 30 10]
  20.     IL_0012: nop

  21.     // [31 13 - 31 54]
  22.     IL_0013: ldarg.0      // this
  23.     IL_0014: ldstr        "HelloDotNetGuide_V2"
  24.     IL_0019: stfld        string 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_applicationName

  25.     // [32 9 - 32 10]
  26.     IL_001e: ret

  27.   } // end of method ConstAndReadonlyExercise::.ctor

  28.   .method public hidebysig static specialname class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'
  29.     get_Instance() cil managed
  30.   {
  31.     .maxstack 2
  32.     .locals init (
  33.       [0] bool V_0,
  34.       [1] object V_1,
  35.       [2] bool V_2,
  36.       [3] class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise' V_3
  37.     )

  38.     // [37 13 - 37 14]
  39.     IL_0000: nop

  40.     // [38 17 - 38 39]
  41.     IL_0001: ldsfld       class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise''HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_instance
  42.     IL_0006: ldnull
  43.     IL_0007: ceq
  44.     IL_0009: stloc.0      // V_0

  45.     IL_000a: ldloc.0      // V_0
  46.     IL_000b: brfalse.s    IL_0040

  47.     // [39 17 - 39 18]
  48.     IL_000d: nop

  49.     // [40 21 - 40 36]
  50.     IL_000e: ldsfld       object 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_lockObj
  51.     IL_0013: stloc.1      // V_1
  52.     IL_0014: ldc.i4.0
  53.     IL_0015: stloc.2      // V_2
  54.     .try
  55.     {
  56.       IL_0016: ldloc.1      // V_1
  57.       IL_0017: ldloca.s     V_2
  58.       IL_0019: call         void [System.Threading]System.Threading.Monitor::Enter(object, bool&)
  59.       IL_001e: nop

  60.       // [41 21 - 41 22]
  61.       IL_001f: nop

  62.       // [42 25 - 42 70]
  63.       IL_0020: ldsfld       class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise''HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_instance
  64.       IL_0025: brtrue.s     IL_0031
  65.       IL_0027: newobj       instance void 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::.ctor()
  66.       IL_002c: stsfld       class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise''HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_instance

  67.       // [43 21 - 43 22]
  68.       IL_0031: nop
  69.       IL_0032: leave.s      IL_003f
  70.     } // end of .try
  71.     finally
  72.     {

  73.       IL_0034: ldloc.2      // V_2
  74.       IL_0035: brfalse.s    IL_003e
  75.       IL_0037: ldloc.1      // V_1
  76.       IL_0038: call         void [System.Threading]System.Threading.Monitor::Exit(object)
  77.       IL_003d: nop

  78.       IL_003e: endfinally
  79.     } // end of finally

  80.     // [44 17 - 44 18]
  81.     IL_003f: nop

  82.     // [45 17 - 45 34]
  83.     IL_0040: ldsfld       class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise''HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_instance
  84.     IL_0045: stloc.3      // V_3
  85.     IL_0046: br.s         IL_0048

  86.     // [46 13 - 46 14]
  87.     IL_0048: ldloc.3      // V_3
  88.     IL_0049: ret

  89.   } // end of method ConstAndReadonlyExercise::get_Instance

  90.   .method public hidebysig static void
  91.     UpdateApplicationNameValue() cil managed
  92.   {
  93.     .maxstack 3
  94.     .locals init (
  95.       [0] class 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise''instance',
  96.       [1] class [System.Runtime]System.Reflection.FieldInfo 'field'
  97.     )

  98.     // [50 9 - 50 10]
  99.     IL_0000: nop

  100.     // [51 13 - 51 59]
  101.     IL_0001: newobj       instance void 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::.ctor()
  102.     IL_0006: stloc.0      // 'instance'

  103.     // [52 13 - 52 68]
  104.     IL_0007: ldstr        "初始值: "
  105.     IL_000c: ldloc.0      // 'instance'
  106.     IL_000d: ldfld        string 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_applicationName
  107.     IL_0012: call         string [System.Runtime]System.String::Concat(string, string)
  108.     IL_0017: call         void [System.Console]System.Console::WriteLine(string)
  109.     IL_001c: nop

  110.     // [55 13 - 55 73]
  111.     IL_001d: ldloc.0      // 'instance'
  112.     IL_001e: callvirt     instance class [System.Runtime]System.Type [System.Runtime]System.Object::GetType()
  113.     IL_0023: ldstr        "_applicationName"
  114.     IL_0028: callvirt     instance class [System.Runtime]System.Reflection.FieldInfo [System.Runtime]System.Type::GetField(string)
  115.     IL_002d: stloc.1      // 'field'

  116.     // [56 13 - 56 61]
  117.     IL_002e: ldloc.1      // 'field'
  118.     IL_002f: ldloc.0      // 'instance'
  119.     IL_0030: ldstr        "HelloDotNetGuide_V3"
  120.     IL_0035: callvirt     instance void [System.Runtime]System.Reflection.FieldInfo::SetValue(object, object)
  121.     IL_003a: nop

  122.     // [58 13 - 58 68]
  123.     IL_003b: ldstr        "修改后: "
  124.     IL_0040: ldloc.0      // 'instance'
  125.     IL_0041: ldfld        string 'HelloDotNetGuide.CSharp语法.ConstAndReadonlyExercise'::_applicationName
  126.     IL_0046: call         string [System.Runtime]System.String::Concat(string, string)
  127.     IL_004b: call         void [System.Console]System.Console::WriteLine(string)
  128.     IL_0050: nop

  129.     // [60 9 - 60 10]
  130.     IL_0051: ret

  131.   } // end of method ConstAndReadonlyExercise::UpdateApplicationNameValue
复制代码
C#/.NET/.NET Core面试宝典

本文已收录至C#/.NET/.NET Core面试宝典中,更多C#关键字详解请前往C#/.NET/.NET Core面试宝典开放地址查阅。

  • 面试宝典地址:https://www.yuque.com/ysgstudyhard/da6e0c
2.png

3.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册