本文包含以下便捷语法:
- out 变量
- 元组
- 占位符
- is 模式表达式
- switch 模式表达式
- 本地函数
- 二进制表示和数字分隔符
out 变量
以前,需要将 out 变量的声明、使用为两个不同的语句,如下所示:
int numericResult;
if (int.TryParse(input, out numericResult))
WriteLine(numericResult);
else
WriteLine("Could not parse input");
现在,可将前面两行合并为一行表示:
if (int.TryParse(input, out int result))
WriteLine(result);
else
WriteLine("Could not parse input");
虽然只比之前简洁了一点点,但,有总比没有好吧~
元组
元组是包含多个字段以表示数据成员的轻量级数据结构。
元组在作为 private
和 internal
方法的返回类型时是最有用的,元组为这些方法提供了简单的语法以返回多个离散值,不用再费心定义返回类型的 class
或 struct
。
其注意事项如下:
新的元组功能需要
ValueTuple
类型。 为在不包括该类型的平台上使用它,必须添加NuGet
包System.ValueTuple
。
通过为每个成员赋值,可以创建一个元组, 此赋值会创建其成员为 Item1
和 Item2
的元祖,其使用方式与 Tuple
的相同。:
var letters = ("a", "b");
可更改语法,以创建为每个元组成员提供语义名称的元组,以下namedLetters
元组包含称为 Alpha
和 Beta
的字段。:
// 方式一
(string Alpha, string Beta) namedLetters = ("a", "b");
// 方式二
var namedLetters = (Alpha: "a", Beta: "b");
当用于方法的返回值时,使用方式如下(在一个整数序列中找到的最小值和最大值):
public (int Max, int Min) Range(IEnumerable numbers) {
int min = int.MaxValue;
int max = int.MinValue;
foreach (var n in numbers) {
min = (n < min) ? n : min;
max = (n > max) ? n : max;
}
return (max, min);
}
看,这种方式是不是比以前更方便
放在以前,为了让返回值包含最大值和最小值,还需要创建一个类或结构体;当然,在返回值个数比较少时,依然可以使用
ref
或out
来实现多个值的返回
占位符
方法返回值中的占位
占位符相当于未赋值的变量,它们没有值。被放弃的变量将不为该变量分配存储空间,所以弃元可减少内存分配。
使用场景:假定有如下函数(该函数在一个单独的不可更改的程序集中),该函数用于获取具体位置:
public (string Province, string City, string Address) GetLocation() {
return ("Sichuang", "Chengdu", "Hi-Tech Zone");
}
现我们只需要获取城市,而不需要省份与具体地址,则可以以如下方式调用:
var (_, city, _) = GetLocation();
这样有个好处,可以节省内存,因为系统将不会为 Province
和 City
分配内存。
out 参数中的占位
使用场景:比如我们需要验证用户输入的手机号是否为三大运营商发行的号段,以前是这样的:
string phoneNumber;
if (Utils.ParsePhoneNumber(phoneNumberStr, out phoneNumber)) {
Console.WriteLine("This is a phone number");
} else {
Console.WriteLine("Not a phone number");
}
现在我们可以这样写,除了语法更加简洁,还可以稍微节约点内存(因为我们此处并不需要解析后的号码,这个用户已经输入了,我们仅需要判断是否符合条件即可):
if (Utils.ParsePhoneNumber(phoneNumberStr, out _)) {
Console.WriteLine("This is a phone number");
} else {
Console.WriteLine("Not a phone number");
}
is 模式表达式
is
模式表达式扩展了常用 is
运算符,使其可查询其类型之外的对象。它可以在检查类型过程中编写变量初始化。
object obj = "value";
if (obj is string tmp) {
Console.WriteLine($"obj is a string, value is {tmp}");
}
这部分的意思是,如果 obj
是 string
类型的实例,则分配临时变量 tmp
来保存转换为 string
之后的值。
switch 模式表达式
看代码即可,具体意义同 is 模式表达式:
public static int DiceSum4(IEnumerable
本地函数
使用场景:当某一函数 A 需要通过另一个函数 B 来进行更加复杂的处理,但其他地方都不会用到 B,此时,我们可以将 B 声明在 A 的内部,示例如下:
public static IEnumerable AlphabetSubset3(char start, char end) {
if (start < 'a' || start > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
if (end < 'a' || end > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");
if (end <= start)
throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}");
return alphabetSubsetImplementation();
IEnumerable alphabetSubsetImplementation() {
for (var c = start; c < end; c++)
yield return c;
}
}
本地方法仅在外部方法的上下文中引用。本地函数的规则还确保开发人员不会意外地从类中的另一个位置调用本地函数和绕过参数验证。
二进制表示和数字分隔符
在创建位掩码时,或每当数字的二进制表示形式使代码最具可读性时, 可使用二进制进行表示,常量开头的 0b 表示该数字以二进制数形式写入。示例如下:
public const int One = 0b0001;
public const int Two = 0b0010;
public const int Four = 0b0100;
public const int Eight = 0b1000;
如果二进制很长,可通过 _ 作为数字分隔符通常更易于查看,如下:
public const int Sixteen = 0b0001_0000;
public const int ThirtyTwo = 0b0010_0000;
public const int SixtyFour = 0b0100_0000;
public const int OneHundredTwentyEight = 0b1000_0000;
数字分隔符可以出现在常量的任何位置:
// 对于十进制数字,通常将其用作千位分隔符
public const long BillionsAndBillions = 100_000_000_000;
// 数字分隔符也可以与 decimal、float 和 double 类型一起使用
public const double AvogadroConstant = 6.022_140_857_747_474e23;
public const decimal GoldenRatio = 1.618_033_988_749_894_848_204_586_834_365_638_117_720_309_179M;
这样,可读性就很强了。
至此,本节内容讲解完毕。欢迎关注公众号【嘿嘿的学习日记】,所有的文章,都会在公众号首发;或加个人微信【JameLee6292】共同探讨。谢谢您咯~
公众号二维码如下: