Break
终止 for、foreach、while 和 do 迭代循环,或者 switch。break 将仅终止其所在的循环或选择。若有循环外或选择外语句,控制权交给终止语句后面的语句。
最简单的
private static void FF基础的Break ( )
{
int [ ] Zhss = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ];
foreach ( int z in Zhss )
{
if ( z == 6 )
{
break;
}
Console . Write ( $"{z}," );
}
Console . WriteLine ( );
Console . WriteLine ( "例程结束。" );
}
输出结果:
1,2,3,4,5,
例程结束。
你可以把代码中的 ( z == 6 ) 中的 6 改为任意大于 1 且小于 9 的自然数,以输出它们。break 语句将在 z 等于指定的数值时退出 foreach 循环。
嵌套的循环
当循环中包括循环时,break 只终止包含它的循环。例如:
private static void FF嵌套的break ( )
{
for ( int Q = 1 ; Q < 10 ; Q++ )
{
for ( int H = 1 ; H < 10 ; H++ )
{
if ( H > Q )
{
break; // 终止 H 循环,继续 Q 循环
}
Console . Write ( $"{H}\t" );
}
Console . WriteLine ( );
}
}
例程中的 break 只终止 H 循环,继续 Q 循环。
终止 switch
下面这个例程是个伪代码,意即当你的屋里温度不适宜的时候的空调启动过程:
double 室温 = 空调 . FF获取室温 ( );
switch ( 室温 )
{
case < 15:
空调 . 升温 ( );
break;
case > 26:
空调 . 降温 ( );
break;
case double . NaN:
Console . WriteLine ( "空调坏了!" );
break;
default:
Console . WriteLine ( $"室内温度:{室温}" );
break;
}
假设这是一个空调的控制程序(具有完备的启动程序和温度测试程序),那么室温在 15℃ 以下会升温,26℃ 以上会降温。否则只是显示室温而不工作。
break(或其他跳转语句)只是在完成 switch 选择的过程后退出该选择过程,如果没有跳转语句,C# 不知道如何退出去,将会提示 CS0163 编译错误,必须使用 break、return、goto、continue 或 throw 等关键字终止该节。否则 C# 会认为 switch 贯穿下一个条件了。
continue
当某个循环(for、foreach、while 或 do)遇到 continue 语句,当前循环是被抛弃的,但要继续下一次循环。例如:
for ( int z = 1 ; z <= 15 ; z++ )
{
Console . Write ( $"操作数:{z}" )
if ( z % 5 = 0 )
{
Console . WriteLine ( $"5 的倍数:{z}" );
}
else
{
Console . WriteLine ( $"不是 5 的倍数:{z}" );
continue;
}
上例中的 continue 其实没用。但当你的循环需要大量的操作而其实无效时,continue 可以节省大量工作时间。
retrun
return 是返回结果的指令。它会立刻退出当前代码所在的函数、方法等,把控制权交还给调用方,并且若是有函数结果,一并还给调用方。
例如,下面的函数将返回一个圆的面积,或者返回零:
public class YuanLei ( double 半径 )
{
private readonly double _半径;
public double SX面积 ( )
{
return Math . PI * ( Math . Pow ( _半径 , 2 ) );
}
}
下面是没有返回值的 retrun:
static void FF必要的 ( int 数 )
{
if ( 数 % 2 == 0 )
{
return;
}
Console . WriteLine ( 数 );
}
调用下列代码:
Console . Write ( $"第一次调用:" );
FF必要的 ( 5 );
Console . Write ( $"第二次调用:" );
FF必要的 ( 6 );
将产生下列输出:
第一次调用:5
第二次调用:
意即第一次由于参数不是个偶数,而输出数本身,第二次参数是个偶数,则输出 null。
如果 return 语句具有表达式,该表达式必须可隐式转换为函数成员的返回类型,除非它是异步的。 从 async 函数返回的表达式必须隐式转换为 Task<TResult> 或 ValueTask<TResult> 类型参数,以函数的返回类型为准。 如果 async 函数的返回类型为 Task 或 ValueTask,则使用不带表达式的 return 语句。
引用返回
默认情况下,return 语句返回表达式的值。可以返回对变量的引用。引用返回值(或 ref 返回值)是由方法按引用向调用方返回的值。即是调用方可以修改方法所返回的值,此更改反映在所调用方法中的对象的状态中。为此,请使用带 ref 关键字的 return 语句。
借助引用返回值,方法可以将对变量的引用(而不是值)返回给调用方。然后,调用方可以选择将返回的变量视为按值返回或按引用返回。调用方可以新建称为引用本地的变量,其本身就是对返回值的引用。引用返回值是指,方法返回对某变量的引用(或别名)。相应变量的作用域必须包括方法。相应变量的生存期必须超过方法的返回值。调用方对方法的返回值进行的修改应用于方法返回的变量。
如果声明方法返回引用返回值,表明方法返回变量别名。设计意图通常是让调用代码通过别名访问此变量(包括修改它)。方法的引用返回值不得包含返回类型 void。
为方便调用方修改对象的状态,引用返回值必须存储在被显式定义为 reference 变量的变量中。
ref 返回值是被调用方法范围中另一个变量的别名。 可以将引用返回值的所有使用都解释为,使用它取别名的变量:
- 分配值时,就是将值分配到它取别名的变量。
- 读取值时,就是读取它取别名的变量的值。
- 如果以引用方式返回它,就是返回对相同变量所取的别名。
- 如果以引用方式将它传递到另一个方法,就是传递对它取别名的变量的引用。
- 如果返回引用本地别名,就是返回相同变量的新别名。
引用返回必须是调用方法的 ref-safe-context。也就是说:
- 返回值的生存期必须长于方法执行时间。换言之,它不能是返回自身的方法中的本地变量。它可以是实例或类的静态字段,也可是传递给方法的参数。尝试返回局部变量将生成编译器错误 CS8168:“无法按引用返回局部 "obj",因为它不是 ref 局部变量”。
- 返回值不得为文本 null。 使用引用返回值的方法可以返回值当前为 null(未实例化)或可为空的值类型的变量别名。
- 返回值不得为常量、枚举成员、通过属性的按值返回值或 class/struct 方法。
此外,禁止对异步方法使用引用返回值。异步方法可能会在执行尚未完成时就返回值,尽管返回值仍未知。
返回引用返回值的方法必须:
- 在返回类型前面有 ref 关键字。
- 方法主体中的每个 return 语句都在返回实例的名称前面有 ref 关键字。
下面定义了书(Shu)类,仅包含书名和作者两项:
/// <summary>
/// 我的书类
/// </summary>
public class Shu
{
public string? 书名 , 作者;
public override string ToString ( )
{
return $"{书名},{作者}";
}
}
下面定义了我的书类(书名和作者都是瞎编的,唯一的“彡”是我的外号)
public class 我的书
{
private Shu [ ] MB = [ new Shu { 书名 = "水瓶传" , 作者 = "施大娘" } , new Shu { 书名 = "五胡演义" , 作者 = "彡"} ];
private Shu Mei = null;
public ref Shu FF自书名获取书籍 ( string 书名 )
{
for ( int z = 0 ; z < MB . Length ; z++ )
{
if ( 书名 == MB [ z ] . 书名 )
{
return ref MB [ z ];
}
}
return ref Mei;
}
public void FF书籍列表 ( )
{
foreach ( Shu S in MB )
{
Console . WriteLine ( $"{S . 书名},作者:{S . 作者}" );
}
Console . WriteLine ( );
}
}
执行下列操作后:
var Shus = new 我的书 ( );
Shus . FF书籍列表 ( );
显示结果:
水瓶传,作者:施大娘
五胡演义,作者:彡
执行下列操作后:
ref var S = ref Shus . FF自书名获取书籍 ( "五胡演义" );
if ( S != null )
{
S = new Shu { 书名 = "我的地啊" , 作者 = "翔大爷" };
}
Shus . FF书籍列表 ( );
显示结果:
水瓶传,作者:施大娘
我的地啊,作者:翔大爷
代码将 S 描述为我的书籍里面找到的书名为《五胡演义》的,并改成《我的地啊》,作者为“翔大爷”(我儿子)。代码引用了调用方对返回值的修改。
goto
当年玩 Basic 的时候,很烦标签。Basic 自称太不结构化了。不知道为啥 C# 依然留着这个……
首先声明一个词典(Dictionary),表明你学习成绩在排名上的变化:
Dictionary< string , int [ ] [ ] > 学期排名 = new ( )
{
["上学期"] = [ [1, 2, 3, 4], [4, 3, 2, 1] ],
["下学期"] = [ [5, 6, 7, 8], [8, 7, 6, 5] ],
};
然后检查名次:
private static void FF检查名次 ( Dictionary< string , int [ ] [ ] > 查找名次 , int 名次 )
{
foreach ( var (YCH, Zhi) in 查找名次 )
{
for ( int H = 0 ; H < Zhi . Length ; H++ )
{
for ( int L = 0 ; L < Zhi [ H ] . Length ; L++ )
{
if ( Zhi [ H ] [ L ] == 名次 )
{
goto 找到啦; // 转移到“找到啦”
}
}
}
Console . WriteLine ( $"在 {YCH} 中找不到你的名次 {名次}" );
continue;
找到啦: // 这是找到啦的转移位置
Console . WriteLine ( $"在 {YCH} 中找到你的名次 {名次}" );
}
}
C# FF检查名次 ( 学期排名 , 4 );
的结果为:
在 上学期 中找到你的名次 4
在 下学期 中找不到你的名次 4
在 switch 中,可以使用 goto default; 将控制权转移到 default 标签的 switch 节。
如果当前函数成员中不存在具有给定名称的标签,或者 goto 语句不在标签范围内,则会出现编译时错误。 也就是说,你不能使用 goto 语句将控制权从当前函数成员转移到任何嵌套范围。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。