C# 常量
常量(Constant)是在程序中定义后不能重新赋值的值,通常用于表示固定不变的数据,例如圆周率、最大连接数、状态标识等。
在 C# 中,可以使用 const 关键字声明编译时常量,也可以通过整数、浮点数、字符、字符串等字面量直接表示固定值。
本章节主要介绍 C# 中常见的常量类型、字面量写法,以及如何使用 const 定义常量。
整数常量
整数常量用于表示没有小数部分的整数。在 C# 中,整数字面量支持以下三种进制:
- 十进制:直接使用数字表示,例如
100、255。 - 十六进制:使用
0x或0X前缀,例如0xFF。 - 二进制:使用
0b或0B前缀,例如0b1010。
注意:C# 不支持 C/C++ 中通过前导数字 0 表示八进制整数的写法。例如,0213 在 C# 中表示十进制整数 213,而不是八进制数。
以下是一些合法的整数常量:
212 // 十进制整数 0xFF // 十六进制,等于十进制 255 0b1010 // 二进制,等于十进制 10 215U // 无符号整数 100L // long 类型整数 100UL // ulong 类型整数 1_000_000 // 使用下划线分隔数字,提高可读性
以下是一些不合法的整数常量:
0b102 // 非法:二进制只能包含 0 和 1 0xFG // 非法:G 不是十六进制数字 032UU // 非法:不能重复使用 U 后缀 123_ // 非法:下划线不能放在数字末尾
整数常量可以使用类型后缀,后缀不区分大小写:
| 后缀 | 含义 | 示例 |
|---|---|---|
| 无后缀 | 根据数值大小依次选择能够容纳该值的整数类型 | 100 |
U 或 u | 优先使用 uint,超出范围时可使用 ulong | 100U |
L 或 l | 优先使用 long,必要时可使用 ulong | 100L |
UL 或 LU | 使用 ulong 类型 | 100UL |
通常建议使用大写的 L,避免小写字母 l 与数字 1 混淆。
以下实例演示不同进制的整数常量:
实例
class Program
{
static void Main()
{
int decimalNumber = 42;
int hexNumber = 0x2A;
int binaryNumber = 0b101010;
Console.WriteLine("十进制:" + decimalNumber);
Console.WriteLine("十六进制:" + hexNumber);
Console.WriteLine("二进制:" + binaryNumber);
}
}
执行结果:
十进制:42 十六进制:42 二进制:42
虽然三个整数采用了不同的进制表示,但它们的实际数值相同。
浮点常量
浮点常量用于表示带有小数部分或采用科学计数法表示的数值,例如 3.14、0.5 和 1.5e3。
在 C# 中,浮点数字面量可以包含整数部分、小数部分和指数部分,也可以使用科学计数法表示。
科学计数法使用 e 或 E 表示以 10 为底的指数,例如:
1.5e3 // 1.5 × 10³,即 1500 2.5E-2 // 2.5 × 10⁻²,即 0.025
C# 提供三种常用的浮点数类型:
| 类型 | 后缀 | 示例 | 说明 |
|---|---|---|---|
float | F 或 f | 3.14f | 单精度浮点数,约 6~9 位有效数字 |
double | D 或 d(可省略) | 3.14 | 双精度浮点数,约 15~17 位有效数字 |
decimal | M 或 m | 3.14m | 十进制高精度数值类型,适合金额等计算 |
以下是一些合法的浮点常量:
3.14159 // 合法,double 类型 3.14f // 合法,float 类型 3.14m // 合法,decimal 类型 314159E-5 // 合法,科学计数法 210f // 合法,float 类型,值为 210 1.5e3 // 合法,值为 1500 0.25D // 合法,double 类型
以下是不合法的浮点常量:
510E // 非法:指数部分缺少数字 .e55 // 非法:小数点前后都没有有效数字 3.14L // 非法:L 只能作为整数后缀 1.2.3 // 非法:包含多个小数点
注意:没有后缀的实数字面量默认是 double 类型。如果要将带小数的字面量赋值给 float 或 decimal 变量,通常需要添加 f 或 m 后缀。
实例
class Program
{
static void Main()
{
float a = 3.14f;
double b = 3.1415926;
decimal c = 99.99m;
double d = 1.5e3;
Console.WriteLine("float: " + a);
Console.WriteLine("double: " + b);
Console.WriteLine("decimal: " + c);
Console.WriteLine("科学计数法: " + d);
}
}
执行结果(在使用点号作为小数分隔符的区域设置下):
float: 3.14 double: 3.1415926 decimal: 99.99 科学计数法: 1500
对于金额等需要十进制精确计算的场景,通常建议使用 decimal 类型。但需要注意,任何数值类型都有其表示范围和精度限制。
字符常量
字符常量使用单引号 '' 表示,例如 'A'、'9'、'中'。
在 C# 中,字符字面量的类型为 char,表示一个 UTF-16 代码单元。
字符常量可以是普通字符,也可以是转义序列,例如 '\n' 表示换行符、'\t' 表示水平制表符。
常用的字符转义序列如下:
| 转义序列 | 含义 |
|---|---|
\\ | 反斜杠字符 \ |
\' | 单引号字符 ' |
\" | 双引号字符 " |
\0 | 空字符(Null) |
\a | 响铃字符(Alert) |
\b | 退格符(Backspace) |
\f | 换页符(Form Feed) |
\n | 换行符(Line Feed) |
\r | 回车符(Carriage Return) |
\t | 水平制表符(Tab) |
\v | 垂直制表符(Vertical Tab) |
\xhh | 十六进制转义,支持 1~4 位十六进制数字 |
\uhhhh | 使用 4 位十六进制数字表示 Unicode 代码单元 |
\Uhhhhhhhh | 使用 8 位十六进制数字表示 Unicode 码点 |
注意:C# 不支持 C 语言中的 \ooo 八进制字符转义序列,也不支持 \? 转义序列。需要表示问号时,可以直接使用 '?'。
另外,char 只能表示一个 UTF-16 代码单元。部分 Unicode 字符(例如许多 Emoji)需要两个 UTF-16 代码单元,不能直接使用单个 char 保存,可以使用 string。
以下实例演示常见的字符转义序列:
实例
class Program
{
static void Main()
{
char letter = 'A';
char chinese = '中';
char unicodeChar = '\u4E2D';
Console.WriteLine("普通字符:" + letter);
Console.WriteLine("中文字符:" + chinese);
Console.WriteLine("Unicode 字符:" + unicodeChar);
Console.WriteLine("Hello\tWorld");
Console.WriteLine("第一行\n第二行");
Console.WriteLine("双引号:\"");
Console.WriteLine("反斜杠:\\");
}
}
执行结果:
普通字符:A 中文字符:中 Unicode 字符:中 Hello World 第一行 第二行 双引号:" 反斜杠:\
其中,\t 表示水平制表符,实际显示的空白宽度由终端环境决定;\n 表示换行。
字符串常量
字符串用于表示一组字符。在 C# 中,字符串类型为 string,普通字符串字面量使用双引号 "" 包围。
C# 支持普通字符串、逐字字符串、插值字符串以及原始字符串等多种写法。
1、普通字符串
普通字符串使用双引号表示,支持 \n、\t、\\ 等转义序列。
string a = "hello, world"; string b = "Hello\nWorld"; string c = "Joe said \"Hello\" to me"; string d = "C:\\Users\\Public\\Documents";
2、逐字字符串
逐字字符串在双引号前添加 @,通常不需要对反斜杠进行转义,特别适合表示 Windows 文件路径、正则表达式等内容。
string a = @"hello, world"; string b = @"C:\Users\Public\Documents"; string c = @"Joe said ""Hello"" to me"; string d = @"\\server\share\file.txt";
在逐字字符串中,反斜杠按普通字符处理。如果需要包含双引号,可以使用两个连续的双引号 ""。
3、插值字符串
插值字符串使用 $ 前缀,可以直接将变量或表达式嵌入字符串中,避免频繁使用字符串拼接。
string name = "Runoob";
int age = 10;
string message = $"名称:{name},年龄:{age}";
4、原始字符串
从 C# 11 开始,可以使用三个或更多双引号定义原始字符串字面量(Raw String Literal)。
原始字符串可以直接包含反斜杠和双引号,适合表示 JSON、HTML、SQL 等多行文本。
string json = """
{
"name": "Runoob",
"language": "C#"
}
""";
以上代码中的双引号不需要使用反斜杠转义。原始字符串中的换行与缩进遵循 C# 原始字符串的语法规则。
以下是常见字符串写法的对比:
| 字符串类型 | 语法 | 主要用途 |
|---|---|---|
| 普通字符串 | "Hello" | 普通文本、转义字符 |
| 逐字字符串 | @"C:\Temp" | 文件路径、正则表达式、多行文本 |
| 插值字符串 | $"Hello {name}" | 在字符串中插入变量或表达式 |
| 原始字符串 | """Hello""" | JSON、HTML、SQL 等文本,要求 C# 11+ |
下面通过一个实例演示普通字符串、逐字字符串和插值字符串的使用:
实例
class Program
{
static void Main()
{
string name = "Runoob";
// 普通字符串
string a = "Hello\nWorld";
// 逐字字符串
string b = @"C:\Users\Public";
// 插值字符串
string c = $"Hello, {name}!";
// 字符串拼接
string d = "Hello, " + "World!";
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
}
}
执行结果:
Hello World C:\Users\Public Hello, Runoob! Hello, World!
注意:C# 不会自动将两个相邻的字符串字面量拼接成一个字符串。如果需要组合多个字符串,可以使用 + 运算符、插值字符串或者其他字符串处理方法。
定义常量
在 C# 中,可以使用 const 关键字定义常量。
常量必须在声明时进行初始化,并且初始化表达式必须是编译时能够确定的常量表达式。一旦定义,不能重新赋值。
定义常量的基本语法如下:
const 数据类型 常量名称 = 常量表达式;
例如:
const int MaxCount = 100; const double Pi = 3.1415926; const string SiteName = "Runoob"; const bool IsEnabled = true;
需要注意,const 并不能用于所有数据类型。通常可以用于数值类型、bool、char、string 和枚举类型。其他引用类型只能声明值为 null 的常量。
对于需要在程序运行时确定初始值的数据,可以考虑使用 readonly。
下面的代码演示了如何在程序中定义和使用常量:
实例
public class ConstTest
{
class SampleClass
{
public int x;
public int y;
// 定义常量
public const int c1 = 5;
public const int c2 = c1 + 5;
public SampleClass(int p1, int p2)
{
x = p1;
y = p2;
}
}
static void Main()
{
SampleClass mC = new SampleClass(11, 22);
Console.WriteLine("x = {0}, y = {1}", mC.x, mC.y);
Console.WriteLine("c1 = {0}, c2 = {1}",
SampleClass.c1, SampleClass.c2);
}
}
当上面的代码被编译和执行时,它会产生下列结果:
x = 11, y = 22 c1 = 5, c2 = 10
程序分析:
x和y是普通实例字段,可以在程序运行时修改。c1是使用const定义的整数常量,值为 5。c2通过常量表达式c1 + 5初始化,编译时即可确定其值为 10。- 类中的
const成员隐式为静态成员,因此可以通过类名访问,例如SampleClass.c1。
如果尝试修改已经定义的常量,例如:
const int MaxCount = 100; // 以下代码会产生编译错误 MaxCount = 200;
编译器会提示常量不能被重新赋值。
const 与 readonly 的区别
在 C# 中,const 和 readonly 都可用于限制字段的修改,但它们的初始化时机和使用范围不同。
| 对比项 | const | readonly |
|---|---|---|
| 初始化时间 | 编译时 | 运行时也可以初始化 |
| 是否必须在声明时赋值 | 是 | 否,也可以在构造函数中赋值 |
| 是否可以修改 | 不能重新赋值 | 初始化后不能在普通代码中重新赋值 |
| 支持的类型 | 仅支持符合常量声明规则的类型 | 支持更多数据类型 |
| 是否属于静态成员 | 类中的 const 成员隐式为静态 | 可以是实例字段,也可以声明为 static readonly |
| 典型用途 | 固定数学常量、状态标识等 | 运行时初始化后不再重新赋值的字段 |
以下实例演示 const 和 readonly 的区别:
实例
class Program
{
// 编译时常量
const double Pi = 3.14159;
// 只读字段
readonly DateTime createdAt;
// 在构造函数中初始化 readonly 字段
public Program()
{
createdAt = new DateTime(2026, 1, 1);
}
static void Main()
{
Program obj = new Program();
Console.WriteLine("圆周率:" + Pi);
Console.WriteLine(
"创建日期:" + obj.createdAt.ToString("yyyy-MM-dd")
);
}
}
执行结果:
圆周率:3.14159 创建日期:2026-01-01
在这个实例中,Pi 是编译时常量,而 createdAt 是在对象创建时通过构造函数初始化的只读字段。
注意:对于引用类型的 readonly 字段,不能在初始化完成后将字段重新指向另一个对象,但这并不意味着引用对象内部的数据一定不能修改。
总结:C# 中的字面量用于直接表示固定值,而 const 可以为编译时常量指定具有明确含义的名称。对于编译时能够确定且长期不变的值,可以使用 const;对于需要在运行时初始化、之后不允许重新赋值的字段,可以使用 readonly。
