现在位置: 首页 > C# 教程 > 正文

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,超出范围时可使用 ulong100U
L 或 l优先使用 long,必要时可使用 ulong100L
UL 或 LU使用 ulong 类型100UL

通常建议使用大写的 L,避免小写字母 l 与数字 1 混淆。

以下实例演示不同进制的整数常量:

实例

using System;

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# 提供三种常用的浮点数类型:

类型后缀示例说明
floatF 或 f3.14f单精度浮点数,约 6~9 位有效数字
doubleD 或 d(可省略)3.14双精度浮点数,约 15~17 位有效数字
decimalM 或 m3.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 后缀。

实例

using System;

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。

以下实例演示常见的字符转义序列:

实例

using System;

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+

下面通过一个实例演示普通字符串、逐字字符串和插值字符串的使用:

实例

using System;

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。

下面的代码演示了如何在程序中定义和使用常量:

实例

using System;

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 都可用于限制字段的修改,但它们的初始化时机和使用范围不同。

对比项constreadonly
初始化时间编译时运行时也可以初始化
是否必须在声明时赋值是否,也可以在构造函数中赋值
是否可以修改不能重新赋值初始化后不能在普通代码中重新赋值
支持的类型仅支持符合常量声明规则的类型支持更多数据类型
是否属于静态成员类中的 const 成员隐式为静态可以是实例字段,也可以声明为 static readonly
典型用途固定数学常量、状态标识等运行时初始化后不再重新赋值的字段

以下实例演示 const 和 readonly 的区别:

实例

using System;

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。