ZetCode

C# 词法结构

最后修改于 2025 年 5 月 16 日

与人类语言一样,计算机语言也具有明确定义的词法结构。 C# 程序的源代码由标记(tokens)组成,这些标记是代码中最小的含义元素。 标记包括标识符(例如变量和方法名称)、关键字(保留字,如 ifclasspublic)、字面量(固定值,如数字和字符串)、运算符(如 +-=)、分隔符(如括号、大括号、逗号和分号)、注释和空白。 C# 编译器读取源代码并将其分解为这些标记,以正确理解和处理程序。

C# 程序使用 Unicode 字符集中的字符编写,该字符集允许使用来自世界各地多种语言的各种符号和脚本。 这意味着 C# 源代码不仅可以包含标准的拉丁字母和数字,还可以包含来自其他字母表、数学符号,甚至是表情符号的字符。 Unicode 支持使开发人员能够使用他们的母语编写标识符和字符串字面量,使 C# 成为一种全球可访问的编程语言。

C# 注释

注释供人类用于阐明源代码。 C# 中有三种类型的注释。 单行注释、多行注释和 XML 注释。 XML 注释可以提取到 HTML 文件。

多行注释用 /* */ 字符括起来。 单行注释以两个正斜杠开头。

Program.cs
/*
    This is Program.cs
    Author: Jan Bodnar
    ZetCode 2022
*/

// A C# statement
Console.WriteLine("This is Comments program");

C# 编译器会忽略注释。

/*
  This is Program.cs
/*  Author: Jan Bodnar */
  ZetCode 2022
*/

注释不能嵌套; 上面的代码无法编译。

C# 空白

C# 中的空白指的是源代码中使用的空格、制表符和换行符。 它有两个主要目的:分隔编译器的标记和提高开发人员的代码可读性。

空白的作用

在某些地方需要空白来区分关键字、标识符和符号。 它还可以提高代码的清晰度,使其更易于阅读和维护。 虽然在某些情况下是必需的,但过多的空白不会影响编译。

int i = 0;
string message = "Hello, World!";

在此示例中,空白将 int 关键字与变量名 i 分隔开,确保编译器正确解释每个标记。

C# 中的空白规则

空白必须放置在类型声明及其标识符之间,例如 int value。 但是,它不能在关键字或变量名中使用——int my Variable 是无效的。 编译器会忽略标记之间的额外空格。 适当的格式可以提高可读性,而不一致的间距会使代码难以阅读。

int a=1;   // No space around '=' (valid but less readable)
int b = 2; // Proper spacing improves clarity
int c  =  3; // Extra spaces do not affect compilation

空白的最佳实践

使用一致的缩进和间距可以提高可读性。 遵循标准的 C# 编码约定(例如在运算符周围放置空格)可以增强清晰度。 避免不必要的空白,因为它不会有助于更好的结构。

// Poorly formatted code:
if(x==10){Console.WriteLine("Hello");}

// Well-formatted code:
if (x == 10)
{
    Console.WriteLine("Hello");
}

尽管编译器会忽略多余的空白,但结构良好的代码可以提高可维护性和可读性,确保以更专业和更有组织的方式进行 C# 开发。

C# 变量

变量是一个标识符,它引用保存值的内存位置。 变量在程序执行期间被赋值。 标识符可以包含字母、数字和下划线,但必须以字母或下划线开头,不能以数字开头。

C# 区分大小写,因此 NamenameNAME 是不同的变量。 关键字不能用作标识符,除非以 @ 为前缀(例如,@int),但不建议这样做。

string userName;
int _count;
DateTime birthDate;

这些是有效的标识符。

string 123name; // Starts with a digit
int %count;     // Contains invalid character
DateTime birth date; // Contains space

这些是无效的标识符。

VariablesExample.cs
public class VariablesExample
{
    public static void Main(string[] args)
    {
        string name = "Robert";
        string Name = "Julia";
        Console.WriteLine(name); // Outputs: Robert
        Console.WriteLine(Name); // Outputs: Julia
    }
}

该程序演示了区分大小写,因为 nameName 被视为单独的变量。

C# 字面量

字面量是给定类型中特定值的直接表示。 C# 支持各种字面量类型,包括布尔值、整数、浮点数、字符串、字符和日期。 与在运行时接收其值的变量不同,字面量在编译时被赋值。

int age = 29;
string nationality = "Hungarian";

在上面的示例中,29 是一个整数文字,而 "Hungarian" 是一个字符串文字。

Program.cs
bool isSingle = true;
string name = "James";
string job = null;
double weight = 68.5;
DateTime birthDate = DateTime.Parse("November 12, 1987");

Console.WriteLine($"His name is {name}");

if (isSingle)
{
    Console.WriteLine("He is single");
}
else
{
    Console.WriteLine("He is in a relationship");
}

Console.WriteLine($"His job is {job}");
Console.WriteLine($"He weighs {weight} kilograms");
Console.WriteLine($"He was born in {birthDate:yyyy}");

上面的示例演示了不同的字面量类型

$ dotnet run
His name is James
He is single
His job is
He weighs 68.5 kilograms
He was born in 1987

C# 运算符

运算符是一个符号,用于对某个值执行操作。 运算符用于表达式中,以描述涉及一个或多个操作数的操作。

+    -    *    /    %    ^    &    |    !    ~
=    +=   -=   *=   /=   %=    ^=    ++    --
==   !=    <   >    &=  >>=   <<=   >=   <=
||   &&    >>    <<    ?:

这是 C# 运算符的部分列表。 我们将在本教程的后面部分讨论运算符。

C# 分隔符

分隔符是一个或多个字符的序列,用于指定纯文本或其他数据流中各个独立区域之间的边界。

[ ]   ( )   { }   ,   :   ;
string language = "C#";

双引号字符用于标记字符串的开头和结尾。 分号 (;) 字符用于结束每个 C# 语句。

Console.WriteLine("Today is {0}", DateTime.Today.ToString("M/d"));

括号(圆括号)用于标记方法签名。 签名由方法参数组成。 大括号用于表示计算后的值。

int[] array = new int[5] {1, 2, 3, 4, 5};

方括号 [] 用于表示数组类型。 它们也用于访问或修改数组元素。 大括号 {} 也用于初始化数组。 大括号也用于变量内插或括住方法或类的主体。

int a, b, c;

逗号字符可用于在同一行代码上使用多个声明。

C# 关键字

C# 中的关键字是保留字,在语言中具有特殊含义。 它们用于定义变量、控制程序流程和执行逻辑运算,从而确保结构化和功能性的代码库。

C# 包括广泛的关键字,例如 ifelseforwhilebasefalsefloatcatchthis。 这些关键字在编程的各个方面发挥着至关重要的作用,并在整个教程中逐步介绍。

Program.cs
for (int i = 0; i <= 5; i++)
{
    Console.WriteLine(i);
}

在上面的示例中,int 关键字定义了一个变量类型,而 for 关键字启动了一个循环,演示了 C# 中的基本控制流和数据处理。

C# Unicode 支持

C# 使用 Unicode 字符集,允许标识符、字面量和注释包含来自各种语言的字符,例如西里尔语、中文或阿拉伯语。 这使得 C# 适用于国际化。

UnicodeExample.cs
public class UnicodeExample
{
    public static void Main(string[] args)
    {
        string имя = "Анна"; // Russian identifier and string
        Console.WriteLine($"Имя: {имя}");
        string 名前 = "太郎"; // Japanese identifier and string
        Console.WriteLine($"名前: {名前}");
    }
}

此示例在俄语和日语中使用 Unicode 标识符和字面量,演示了 C# 对全局字符集的支持。

C# 预处理器指令

预处理器指令是在编译之前处理的特殊指令。 它们允许条件编译、符号定义和其他编译时行为。 所有预处理器指令都以 # 开头。

这些指令不生成可执行代码,但会影响编译器处理源代码的方式。 常见的预处理器指令包括 #define#if#else#elif#endif#region#pragma

PreprocessorExample.cs
#define DEBUG

public class PreprocessorExample
{
    public static void Main(string[] args)
    {
        #if DEBUG
            Console.WriteLine("Debug mode is active");
        #else
            Console.WriteLine("Debug mode is inactive");
        #endif
    }
}

在上面的例子中

预处理器指令对于管理调试和发布配置、组织代码块以及增强编译器行为而无需更改运行时执行非常有用。

C# 行终止符

行终止符标记源代码中一行的结束。 在 C# 中,有效的行终止符包括回车符 (\r)、换行符 (\n) 或组合 (\r\n)。 它们会影响编译器解析标记的方式。

与某些语言不同,C# 不需要用分号终止每一行,但语句必须用分号分隔。 行终止符有助于编译器识别标记边界。

LineTerminatorExample.cs
public class LineTerminatorExample
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Line 1");
        Console.WriteLine("Line 2");
    }
}

每个语句都以分号结尾,并用行终止符分隔,确保编译器正确解析。

C# 约定

约定是编写一致且可读的 C# 代码的推荐做法。 虽然编译器不强制执行这些约定,但它们可以提高代码的可维护性和协作性。 以下是 C# 的主要约定

本文探讨了 C# 的词法结构,包括注释、变量、字面量、运算符、分隔符和关键字等标记。 还涵盖了 Unicode 支持、预处理器指令和行终止符等其他主题,以提供全面的理解。 遵守 C# 约定可确保高质量、可维护的代码。

来源

C# 文档

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程