Jump 语句 - break、continue、return 和 goto - C# reference

Jump 语句 - break、continue、return 和 goto - C# reference

跳转语句无条件地转移控制。 该 break 语句 终止最接近的封闭 迭代语句 或 switch 语句。 该 continue 语句 启动最近封闭 迭代语句的新迭代。 该 return 语句 将终止其出现的函数的执行,并将控件返回到调用方。 该 goto 语句 将控件传输到由标签标记的语句。

有关引发异常和无条件传输控件的语句的信息throw,请参阅throw异常处理语句文章的“语句”部分。

break 语句

该break语句终止最近的封闭迭代语句(即,、for、foreachwhile或循环)或doswitch语句。 该 break 语句将控制权转移到终止语句后面的语句(如果有)。

int[] numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

foreach (int number in numbers)

{

if (number == 3)

{

break;

}

Console.Write($"{number} ");

}

Console.WriteLine();

Console.WriteLine("End of the example.");

// Output:

// 0 1 2

// End of the example.

在嵌套循环中 break ,语句只终止包含它的最内部循环,如以下示例所示:

for (int outer = 0; outer < 5; outer++)

{

for (int inner = 0; inner < 5; inner++)

{

if (inner > outer)

{

break;

}

Console.Write($"{inner} ");

}

Console.WriteLine();

}

// Output:

// 0

// 0 1

// 0 1 2

// 0 1 2 3

// 0 1 2 3 4

在循环中使用 switch 语句时, break switch 节末尾的语句仅将控制权转移出 switch 语句。 包含语句的 switch 循环不受影响,如以下示例所示:

double[] measurements = [-4, 5, 30, double.NaN];

foreach (double measurement in measurements)

{

switch (measurement)

{

case < 0.0:

Console.WriteLine($"Measured value is {measurement}; too low.");

break;

case > 15.0:

Console.WriteLine($"Measured value is {measurement}; too high.");

break;

case double.NaN:

Console.WriteLine("Failed measurement.");

break;

default:

Console.WriteLine($"Measured value is {measurement}.");

break;

}

}

// Output:

// Measured value is -4; too low.

// Measured value is 5.

// Measured value is 30; too high.

// Failed measurement.

continue 语句

如以下示例所示,该continue语句启动最近封闭迭代语句(即,、for、foreachwhile或do循环)的新迭代:

for (int i = 0; i < 5; i++)

{

Console.Write($"Iteration {i}: ");

if (i < 3)

{

Console.WriteLine("skip");

continue;

}

Console.WriteLine("done");

}

// Output:

// Iteration 0: skip

// Iteration 1: skip

// Iteration 2: skip

// Iteration 3: done

// Iteration 4: done

return 语句

该 return 语句将终止在其中出现的函数的执行,并向调用方返回控件和函数的结果(如果有)。

如果函数成员不计算值,则使用不带表达式的 return 语句,如以下示例所示:

Console.WriteLine("First call:");

DisplayIfNecessary(6);

Console.WriteLine("Second call:");

DisplayIfNecessary(5);

void DisplayIfNecessary(int number)

{

if (number % 2 == 0)

{

return;

}

Console.WriteLine(number);

}

// Output:

// First call:

// Second call:

// 5

如前面的示例所示,通常使用不带表达式的 return 语句提前终止函数成员。 如果函数成员不包含该 return 语句,则会在执行其最后一个语句后终止。

如果函数成员计算值,则可将 return 语句与表达式一起使用,如以下示例所示:

double surfaceArea = CalculateCylinderSurfaceArea(1, 1);

Console.WriteLine($"{surfaceArea:F2}"); // output: 12.57

double CalculateCylinderSurfaceArea(double baseRadius, double height)

{

double baseArea = Math.PI * baseRadius * baseRadius;

double sideArea = 2 * Math.PI * baseRadius * height;

return 2 * baseArea + sideArea;

}

return当语句具有表达式时,该表达式必须隐式转换为函数成员的返回类型,除非它是异步的。 从 async 函数返回的表达式必须隐式转换为函数的类型参数 Task ,或者 ValueTask,无论哪个类型是函数的返回类型。 如果函数的 async 返回类型为 Task 或 ValueTask,则使用不带表达式的 return 语句。

Ref 返回

默认情况下,该 return 语句返回表达式的值。 可以返回对变量的引用。 引用返回值(或 ref 返回)是方法通过调用方引用返回的值。 也就是说,调用方可以修改方法返回的值,该更改反映在调用方法中的对象状态中。 为此,请使用关键字 return 的 ref 语句,如以下示例所示:

int[] xs = new int [] {10, 20, 30, 40 };

ref int found = ref FindFirst(xs, s => s == 30);

found = 0;

Console.WriteLine(string.Join(" ", xs)); // output: 10 20 0 40

ref int FindFirst(int[] numbers, Func predicate)

{

for (int i = 0; i < numbers.Length; i++)

{

if (predicate(numbers[i]))

{

return ref numbers[i];

}

}

throw new InvalidOperationException("No element satisfies the given condition.");

}

引用返回值允许方法将对变量(而不是值)的引用返回给调用方。 然后,调用方可以选择将返回的变量视为由值或引用返回的变量。 调用方可以创建一个新变量,该变量本身是对返回值的引用,称为 ref 局部变量。

引用返回值表示方法返回对某些变量的引用(或别名)。 该变量的范围必须包含该方法。 该变量的生存期必须超出方法的返回范围。 对方法返回值的修改由调用方对方法返回的变量进行了修改。

声明方法返回 引用返回值 表示该方法将别名返回给变量。 设计意向通常是调用代码通过别名访问该变量,包括修改该变量。 按引用返回的方法不能具有返回类型 void。

为了使调用方修改对象的状态,必须将引用返回值存储到显式定义为 引用变量的变量。

返回 ref 值是调用方法作用域中另一个变量的别名。 可以将 ref 返回的任何用法解释为使用它别名的变量:

分配其值时,需要为其别名的变量分配一个值。

读取其值时,将读取它别名的变量的值。

如果 按引用返回它,则会向同一变量返回别名。

如果 按引用将其传递给另一个方法,则会向其别名的变量传递引用。

生成 ref 本地 别名时,将创建同一变量的新别名。

ref 返回必须是调用方法 的 ref-safe-context 。 这意味着:

返回值必须具有一个超出方法执行的生存期。 换句话说,它不能是返回它的方法中的局部变量。 它可以是类的实例或静态字段,也可以是传递给方法的参数。 尝试返回本地变量会生成编译器错误 CS8168,“无法按引用返回本地”obj“,因为它不是 ref local。

返回值不能为文本 null。 具有 ref 返回的方法可以将别名返回给当前为 null 值为(未证实的)值或值 类型的可以为 null 的值类型的 变量。

返回值不能是常量、枚举成员、属性中的classstruct按值返回值或方法。

此外,异步方法上不允许引用返回值。 异步方法可能在完成执行之前返回,而其返回值仍然未知。

返回 引用返回值 的方法必须:

在返回类型前面包括 ref 关键字。

方法正文中的每个 return 语句都包含返回实例名称前面的 ref 关键字。

以下示例演示满足这些条件的方法,并返回对 Person 名为 p 的对象的引用:

public ref Person GetContactInformation(string fname, string lname)

{

// ...method implementation...

return ref p;

}

下面是一个更完整的 ref 返回示例,其中显示了方法签名和方法正文。

public static ref int Find(int[,] matrix, Func predicate)

{

for (int i = 0; i < matrix.GetLength(0); i++)

for (int j = 0; j < matrix.GetLength(1); j++)

if (predicate(matrix[i, j]))

return ref matrix[i, j];

throw new InvalidOperationException("Not found");

}

调用的方法还可以将返回值声明为 ref readonly 按引用返回值,并强制调用代码无法修改返回的值。 调用方法可以通过将值存储在本地 ref readonly 引用变量中来避免复制返回的值。

以下示例定义一个具有两String个Book字段的类,Title以及 Author。 它还定义一个 BookCollection 类,该类包含对象的私有数组 Book 。 通过调用单个 GetBookByTitle 书籍对象的方法,通过引用返回。

public class Book

{

public string Author;

public string Title;

}

public class BookCollection

{

private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },

new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }

};

private Book nobook = null;

public ref Book GetBookByTitle(string title)

{

for (int ctr = 0; ctr < books.Length; ctr++)

{

if (title == books[ctr].Title)

return ref books[ctr];

}

return ref nobook;

}

public void ListBooks()

{

foreach (var book in books)

{

Console.WriteLine($"{book.Title}, by {book.Author}");

}

Console.WriteLine();

}

}

当调用方将该方法返回 GetBookByTitle 的值存储为 ref 本地时,调用方对返回值所做的更改将反映在对象中 BookCollection ,如以下示例所示。

var bc = new BookCollection();

bc.ListBooks();

ref var book = ref bc.GetBookByTitle("Call of the Wild, The");

if (book != null)

book = new Book { Title = "Republic, The", Author = "Plato" };

bc.ListBooks();

// The example displays the following output:

// Call of the Wild, The, by Jack London

// Tale of Two Cities, A, by Charles Dickens

//

// Republic, The, by Plato

// Tale of Two Cities, A, by Charles Dickens

goto 语句

该语句将 goto 控件传输到由标签标记的语句,如以下示例所示:

var matrices = new Dictionary

{

["A"] =

[

[1, 2, 3, 4],

[4, 3, 2, 1]

],

["B"] =

[

[5, 6, 7, 8],

[8, 7, 6, 5]

],

};

CheckMatrices(matrices, 4);

void CheckMatrices(Dictionary matrixLookup, int target)

{

foreach (var (key, matrix) in matrixLookup)

{

for (int row = 0; row < matrix.Length; row++)

{

for (int col = 0; col < matrix[row].Length; col++)

{

if (matrix[row][col] == target)

{

goto Found;

}

}

}

Console.WriteLine($"Not found {target} in matrix {key}.");

continue;

Found:

Console.WriteLine($"Found {target} in matrix {key}.");

}

}

// Output:

// Found 4 in matrix A.

// Not found 4 in matrix B.

如前面的示例所示,可以使用 goto 该语句退出嵌套循环。

小窍门

使用嵌套循环时,请考虑将单独的循环重构为单独的方法。 这可能会导致没有 goto 语句的更简单、更易于阅读的代码。

还可以使用goto语句中的switch语句将控件传输到具有常量大小写标签的 switch 节,如以下示例所示:

using System;

public enum CoffeeChoice

{

Plain,

WithMilk,

WithIceCream,

}

public class GotoInSwitchExample

{

public static void Main()

{

Console.WriteLine(CalculatePrice(CoffeeChoice.Plain)); // output: 10.0

Console.WriteLine(CalculatePrice(CoffeeChoice.WithMilk)); // output: 15.0

Console.WriteLine(CalculatePrice(CoffeeChoice.WithIceCream)); // output: 17.0

}

private static decimal CalculatePrice(CoffeeChoice choice)

{

decimal price = 0;

switch (choice)

{

case CoffeeChoice.Plain:

price += 10.0m;

break;

case CoffeeChoice.WithMilk:

price += 5.0m;

goto case CoffeeChoice.Plain;

case CoffeeChoice.WithIceCream:

price += 7.0m;

goto case CoffeeChoice.Plain;

}

return price;

}

}

在语句中 switch ,还可以使用该语句 goto default; 将控件传输到带有标签的 default switch 节。

如果当前函数成员中不存在具有给定名称的标签,或者 goto 该语句不在标签范围内,则会发生编译时错误。 也就是说,不能使用 goto 语句将控制权从当前函数成员转移到任何嵌套作用域中。

C# 语言规范

有关更多信息,请参阅 C# 语言规范的以下部分:

break 语句

continue 语句

return 语句

goto 语句

另请参阅

yield 语句

📚 相关推荐

VPS文件传输指南:FTP、SFTP、SCP与rsync的比较与安全设置,
365bet体育在线赌博

VPS文件传输指南:FTP、SFTP、SCP与rsync的比较与安全设置,

📅 07-28 👁️ 1635
学UI设计前景怎么样啊?我扒了大实话给你听!
365bet体育在线赌博

学UI设计前景怎么样啊?我扒了大实话给你听!

📅 07-18 👁️ 255
怎样加油更优惠
365bet体育在线赌博

怎样加油更优惠

📅 07-30 👁️ 5751
野蛮暴富!你家墙角的路由器到底有多赚钱
365bet体育在线赌博

野蛮暴富!你家墙角的路由器到底有多赚钱

📅 06-30 👁️ 8539
张角简介
365bet娱乐场注册

张角简介

📅 08-26 👁️ 3127
PPT最后几页没法播放?
365bet娱乐场注册

PPT最后几页没法播放?

📅 08-08 👁️ 1327
百度贴吧审核头像多久?深度解析贴吧头像审核机制!
365bet娱乐场注册

百度贴吧审核头像多久?深度解析贴吧头像审核机制!

📅 08-01 👁️ 7793
逆战狙击攻略 实战甩狙练习技巧及心得
英国365

逆战狙击攻略 实战甩狙练习技巧及心得

📅 07-22 👁️ 7412
创造与魔法金龙鱼爆率及最佳钓点位置大全
365bet体育在线赌博

创造与魔法金龙鱼爆率及最佳钓点位置大全

📅 08-09 👁️ 286