Skip to content

语句

C# 作为一种现代化的面向对象编程语言,支持多种类型的语句(Statements),这些语句用于构建程序的逻辑控制结构、数据操作和流程控制。

类别C# 关键字说明
声明语句-声明语句引入新的变量或常量。 变量声明可以选择为变量赋值。 在常量声明中必须赋值。
表达式语句-用于计算值的表达式语句必须在变量中存储该值。
选择语句if,switch选择语句用于根据一个或多个指定条件分支到不同的代码段。
迭代语句for,foreach,while,do-while迭代语句用于遍历集合(如数组),或重复执行同一组语句直到满足指定的条件
跳转语句break,continue,goto,return,yield跳转语句将控制转移给另一代码段。
异常处理语句throw,try-catch,try-finally,try-catch-finally异常处理语句用于从运行时发生的异常情况正常恢复。
checked,unchecked语句-checked 和 unchecked 语句用于指定将结果存储在变量中、但该变量过小而不能容纳结果值时,是否允许整型数值运算导致溢出。
await 语句-如果用 async 修饰符标记方法,则可以使用该方法中的 await 运算符。 在控制到达异步方法的 await 表达式时,控制将返回到调用方,该方法中的进程将挂起,直到等待的任务完成为止。 任务完成后,可以在方法中恢复执行。
fixed 语句-fixed 语句禁止垃圾回收器重定位可移动的变量。 有关详细信息,请参阅 fixed。
lock 语句-lock 语句用于限制一次仅允许一个线程访问代码块。 有关详细信息,请参阅 lock。
空语句-空语句只含一个分号。 不执行任何操作,可以在需要语句但不需要执行任何操作的地方使用。

声明语句

声明语句用于定义变量、常量、方法、类、结构等

C#
// 变量声明
double area;
double radius = 2;

// 一个语句中声明多个相同类型的变量
int a, b, c;

// 常量声明
const double pi = 3.14159;

隐式类型声明

  1. 使用 var 关键字
C#
var greeting = "Hello";

var a = 32;

var xs = new List<double>();
  1. 目标类型化 new
C#
List<int> xs = new();
List<int>? ys = new();
  1. 使用匿名类型
C#
var fromPhoenix = from cust in customers
                  where cust.City == "Phoenix"
                  select new { cust.Name, cust.Phone };

foreach (var customer in fromPhoenix)
{
    Console.WriteLine($"Name={customer.Name}, Phone={customer.Phone}");
}

表达式语句

表达式语句是执行表达式并计算的一种语句。 参考表达式

选择语句

选择语句(也称为条件语句)用于根据表达式的结果或变量的值来控制程序的执行流程。

if 语句

if 语句用于在条件为 true 时执行某段代码。

C#
int number = 5;

if (number > 10)
{
    Console.WriteLine("Number is greater than 10.");
}
else if (number == 5)
{
    Console.WriteLine("Number is exactly 5.");
}
else
{
    Console.WriteLine("Number is less than 10 but not 5.");
}

switch 语句

switch 语句用于根据一个变量的值来选择执行不同的代码块。它通常用于替代多个 else if 语句。

C#
int day = 3;

switch (day)
{
    case 1:
        Console.WriteLine("Monday");
        break;
    case 2:
        Console.WriteLine("Tuesday");
        break;
    case 3:
        Console.WriteLine("Wednesday");
        break;
    case 4:
        Console.WriteLine("Thursday");
        break;
    case 5:
        Console.WriteLine("Friday");
        break;
    default:
        Console.WriteLine("Weekend");
        break;
}

//简洁写法(C# 8.0 引入)
int day = 3;
string dayName = day switch
{
    1 => "Monday",
    2 => "Tuesday",
    3 => "Wednesday",
    4 => "Thursday",
    5 => "Friday",
    _ => "Weekend",
};

更多switch 语句支持的模式的信息,参考模式匹配

迭代语句

迭代语句用于反复执行某段代码,直到满足某个条件。C# 提供了几种常见的迭代语句,包括 for、foreach、while 和 do-while。

for 语句

在指定的布尔表达式的计算结果为 true 时,for 语句会执行一条语句或一个语句块。

C#
for (int i = 0; i < 3; i++)
{
    Console.Write(i);
}
// Output:
// 012

示例展示了 for 语句的元素

  1. 初始化表达式: int i = 0;
  2. 条件: i < 3;
  3. 迭代器: i++;
  4. 循环体:

{ Console.Write(i); }

迭代器

迭代器”部分可包含用逗号分隔的零个或多个以下语句表达式:

  1. 为 increment 表达式添加前缀或后缀,如 ++i 或 i++
  2. 为 decrement 表达式添加前缀或后缀,如 --i 或 i--
  3. 赋值,如 i = k
  4. 方法的调用,如 i = add(a, b)
  5. await表达式, 如 await client.GetByteArrayAsync(url);
  6. 通过使用 new 运算符来创建对象

for 语句的所有部分都是可选的。 例如,以下代码定义无限 for 循环:

C#
for ( ; ; )
{
    //...
}

foreach 语句

foreach 语句为类型实例中实现 System.Collections.IEnumerable 或 System.Collections.Generic.IEnumerable<T> 接口的每个元素执行语句或语句块

C#
List<int> fibNumbers = new() { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibNumbers)
{
    Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13

// ref 或 ref readonly 修饰符声明迭代变量
Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
foreach (ref readonly var item in storage)
{
    Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9

//await foreach
await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

foreach 语句并不限于这些类型

可以将其与满足以下条件的任何类型的实例一起使用:

  1. 类型具有公共无参数 GetEnumerator 方法。 GetEnumerator 方法可以是类型的扩展方法。
  2. GetEnumerator 方法的返回类型具有公共 Current 属性和公共无参数 MoveNext 方法(其返回类型为 bool)。

while 语句

在指定的布尔表达式的计算结果为 true 时,while 语句会执行一条语句或一个语句块。

在每次执行循环之前都会计算此表达式,while 循环会执行零次或多次。

while 循环不同于 do 循环(该循环执行 1 次或多次)。

C#
int n = 0;
while (n < 5)
{
    Console.Write(n);
    n++;
}
// Output:
// 01234

do 语句

在指定的布尔表达式的计算结果为 true 时,do 语句会执行一条语句或一个语句块。

由于在每次执行循环之后都会计算此表达式,所以 do 循环会执行一次或多次。

do 循环不同于 while 循环(该循环执行零次或多次)。

C#
int n = 0;
do
{
    Console.Write(n);
    n++;
} while (n < 5);
// Output:
// 01234

跳转语句

跳转语句用于控制程序的执行流,通常用来提前终止循环、方法或直接跳转到特定的代码部分

break 语句

break 语句用于立即终止最内层的循环或 switch 语句,并跳出该结构。

break 语句通常用在 for、while、do-while 循环和 switch 语句中。

C#
for (int i = 0; i < 10; i++)
{
    if (i == 5)
        break; // 退出循环,当 i == 5 时
    Console.WriteLine(i);
}

continue 语句

continue 语句跳过当前循环的剩余代码,直接开始下一次迭代。

它在循环结构中常用,用于在满足某些条件时跳过循环中的部分代码。

C#
for (int i = 0; i < 10; i++)
{
    if (i % 2 == 0)
        continue; // 跳过偶数,继续下一次循环
    Console.WriteLine(i);
}

return 语句

return 语句用于终止当前方法的执行,并返回到调用该方法的位置。

如果方法有返回值,return 语句可以指定要返回的值。

C#
int Add(int a, int b)
{
    return a + b; // 返回两个数的和
}

void PrintEvenNumbers(int max)
{
    for (int i = 0; i < max; i++)
    {
        if (i % 2 != 0)
            continue; // 只打印偶数
        Console.WriteLine(i);
    }
}

int sum = Add(3, 4); // sum = 7
Console.WriteLine($"Sum: {sum}");

PrintEvenNumbers(10); // 打印 0, 2, 4, 6, 8

goto 语句

goto 语句无条件地跳转到代码中的指定标签位置。尽管 goto 语句可以在某些情况下提供灵活性,但它通常会导致代码难以理解和维护,因此应谨慎使用

C#
int x = 10;

if (x > 5)
{
    goto Label1; // 跳转到 Label1 位置
}

Console.WriteLine("This line will be skipped.");

Label1:
Console.WriteLine("Jumped to Label1");

yield break 语句

yield break 语句用于立即终止迭代器方法的迭代。

与 return 不同,yield break 仅用于迭代器方法中,用来提前结束生成序列。

C#
IEnumerable<int> GetNumbers()
{
    yield return 1;
    yield return 2;

    yield break; // 提前终止迭代

    yield return 3; // 这行代码不会被执行
}

foreach (int number in GetNumbers())
{
    Console.WriteLine(number); // 输出 1, 2
}

yield return 语句

yield return 语句用于迭代器方法中,按顺序返回每个元素。

与 return 语句不同,yield return 允许方法返回一个集合中的多个值,通常用于实现自定义迭代器。

C#
IEnumerable<int> GetEvenNumbers(int max)
{
    for (int i = 0; i <= max; i++)
    {
        if (i % 2 == 0)
            yield return i; // 返回当前偶数
    }
}

foreach (int number in GetEvenNumbers(10))
{
    Console.WriteLine(number); // 输出 0, 2, 4, 6, 8, 10
}

异常处理语句

异常处理语句用于从运行时发生的异常情况正常恢复。 参考异常

checked,unchecked语句

checked 和 unchecked 语句指定整型类型算术运算和转换的溢出检查上下文。

当发生整数算术溢出时,溢出检查上下文将定义发生的情况。

在已检查的上下文中,引发 System.OverflowException;如果在常数表达式中发生溢出,则会发生编译时错误。

在未检查的上下文中,会通过丢弃任何不适应目标类型的高序位来将操作结果截断。

C#
uint a = uint.MaxValue;

unchecked
{
    Console.WriteLine(a + 3);  // output: 2
}

try
{
    checked
    {
        Console.WriteLine(a + 3);
    }
}
catch (OverflowException e)
{
    Console.WriteLine(e.Message);  // output: Arithmetic operation resulted in an overflow.
}

await 语句

如果用 async 修饰符标记方法,则可以使用该方法中的 await 运算符。 在控制到达异步方法的 await 表达式时,控制将返回到调用方,该方法中的进程将挂起,直到等待的任务完成为止。 任务完成后,可以在方法中恢复执行。

参考异步编程

fixed 语句

fixed 语句用于将对象的内存地址固定住,使得垃圾回收器(GC)在 fixed 语句块中不会移动该对象。它通常用于处理指针和非托管代码,确保对象在操作期间保持在内存中的固定位置。

固定数组的内存地址

fixed 语句确保数组 numbers 在循环体中不会被垃圾回收器移动,使得指针 ptr 可以安全地操作该数组。

C#
unsafe // 必须使用 unsafe 关键字,因为指针操作是不安全的
{
    int[] numbers = { 1, 2, 3, 4, 5 };

    fixed (int* ptr = numbers)
    {
        for (int i = 0; i < numbers.Length; i++)
        {
            *(ptr + i) = *(ptr + i) * 2; // 通过指针修改数组元素
        }
    }

    foreach (int num in numbers)
    {
        Console.WriteLine(num); // 输出:2, 4, 6, 8, 10
    }
}

固定字符串的内存地址

字符串在 C# 中是不可变的(immutable),但是在使用非托管代码时,可能需要访问字符串的底层字符数组。

C#
unsafe
{
    string text = "Hello, World!";

    fixed (char* ptr = text)
    {
        for (int i = 0; i < text.Length; i++)
        {
            Console.WriteLine(*(ptr + i)); // 输出字符串的每个字符
        }
    }
}

注意事项

  1. unsafe 关键字:使用 fixed 语句的代码块必须标记为 unsafe,因为指针操作被认为是不安全的。
  2. 性能:fixed 语句会降低垃圾回收器的效率,因为它会限制对象的移动,因此应仅在必要时使用。
  3. 指针指向的对象类型:fixed 语句只适用于托管数组、字符串以及在托管堆上分配的引用类型的字段。

lock 语句

lock 语句用于限制一次仅允许一个线程访问代码块。

参考异步编程

空语句

空语句只含一个分号。 不执行任何操作,可以在需要语句但不需要执行任何操作的地方使用。

Document Base on VitePress.