C# - 常量
C# - 常量和字面量
Section titled “C# - 常量和字面量”在 C# 中,字面量是直接出现在代码中的固定值(例如 101、3.14、"Hello")。常量是定义后其值不能改变的变量。通过为固定值赋予有意义的名称,常量对于创建可读、可维护且无错误的代码至关重要。
C# 提供了两个关键字来声明常量:const 和 readonly。理解它们之间的区别至关重要。
C# 中的字面量
Section titled “C# 中的字面量”整数字面量可以是十进制(基数 10)、十六进制(基数 16,带 0x 前缀)或二进制(基数 2,带 0b 前缀)。你可以使用 U(无符号)、L(长整型)和 UL(无符号长整型)等后缀来指定类型。
int decimalLiteral = 42;long longLiteral = 42L;
// 十六进制 (十进制 255)int hexLiteral = 0xFF;
// 二进制 (十进制 10) - C# 7.0+int binaryLiteral = 0b1010;
// 数字分隔符,提高可读性 - C# 7.0+long bigNumber = 1_000_000_000L;浮点数字面量
Section titled “浮点数字面量”这些表示实数。float 类型使用 f 后缀,double 类型使用 d(可选,因为它是默认值),decimal 类型使用 m(用于高精度金融计算)。
float piFloat = 3.14159f;double piDouble = 3.1415926535;decimal price = 29.99m;字符和字符串字面量
Section titled “字符和字符串字面量”字符字面量用单引号('a')括起来。字符串字面量用双引号("Hello")括起来。C# 提供了几种强大的定义字符串的方式:
// 带有换行符转义序列的标准字符串string standard = "Hello,\nWorld!";
// 逐字字符串:忽略转义序列,适用于文件路径string path = @"C:\Users\Guest\Documents";
// 字符串插值 (C# 6.0+):直接嵌入表达式var name = "Alice";string greeting = $"Hello, {name}!"; // 输出:Hello, Alice!
// 原始字符串字面量 (C# 11+):适用于多行字符串或包含引号的文本string json = """{ "name": "Bob", "age": 30}""";定义常量:const 与 readonly
Section titled “定义常量:const 与 readonly”这是初学者经常混淆的一个点。以下是它们之间的明确区别:
| 特性 | const | readonly |
|---|---|---|
| 初始化 | 必须在声明时初始化。 | 可以在声明时或在构造函数中初始化。 |
| 赋值时间 | 值在编译时设定。 | 值在运行时设定。 |
| 类型支持 | 仅限于内置类型(数值、布尔、字符串、枚举)和 null。 | 可用于任何数据类型,包括自定义类。 |
| 上下文 | 隐式 static。属于类,而非实例。 | 可以是 static(类有一个值)或实例级别(每个对象有一个值)。 |
示例:使用 const
Section titled “示例:使用 const”对那些真正、通用的,永不改变的常量(如数学值)使用 const。
using System;
public class CircleCalculator{ // 编译时常量,通过类名访问 public const double Pi = 3.14159;
public static void Main() { Console.Write("Enter Radius: ");
// 使用 TryParse 进行安全的输入处理 if (double.TryParse(Console.ReadLine(), out double radius) && radius > 0) { double area = CircleCalculator.Pi * radius * radius; Console.WriteLine($"A circle with radius {radius} has an area of {area:F2}."); } else { Console.WriteLine("Invalid input. Please enter a positive number."); } }}示例:使用 readonly
Section titled “示例:使用 readonly”对那些在对象生命周期内固定不变,但可能因每个对象实例而异的值使用 readonly。
using System;
public class User{ // 此值由构造函数设置,之后不能更改。 public readonly Guid UserId; public readonly DateTime CreationTime;
public string Username { get; set; }
public User(string username) { // readonly 字段可以在这里,即构造函数中赋值。 UserId = Guid.NewGuid(); CreationTime = DateTime.UtcNow; Username = username; }
public void DisplayInfo() { Console.WriteLine($"User '{Username}' created on {CreationTime:yyyy-MM-dd} with ID: {UserId}"); }}
public class Program{ public static void Main() { var user1 = new User("jdoe"); user1.DisplayInfo();
// 以下行会导致编译错误: // user1.CreationTime = DateTime.Now; // 错误: readonly 字段不能被赋值(构造函数除外) }}实际应用和最佳实践
Section titled “实际应用和最佳实践”- 避免“魔法数字/字符串”:将代码中未命名的字面量替换为命名常量。
if (userRole == 5)不够清晰,但if (userRole == UserRoles.Administrator)则具有自解释性。 - 配置:使用静态
readonly字段来保存从文件加载的应用程序配置值,这些值在启动时加载。 const用于性能优化:由于const值直接嵌入到编译后的代码(IL)中,访问它们可能略快,但这是一种微优化,通常不具显著意义。readonly用于灵活性:readonly更灵活,通常是更好的选择,除非你有一个真正的编译时常量。