本文包含以下便捷语法:
- 属性在声明处即可进行初始化
- Expression-bodied 函数成员
- using static增强功能
- Null 条件运算符?. ??
- 字符串的格式化
- 异常筛选器
- nameof 表达式
- Catch 和 Finally 块中的 Await
属性在声明处即可进行初始化
在声明它的位置处被初始化。 这样,就能更容易地仅执行一次初始化。 如下:
public string FeatureOne { get; } = "NewFeature_One";
public ICollection<double> Grades { get; } = new List<double>();
public string AutoInit { get; set; } = "Auto Init";
Expression-bodied 函数成员
当我们编写的函数主体只包含一条可以表示为表达式的语句时,可通过改为编写 expression-bodied 成员来简化该语法。 比如:
public override string ToString() => $"{LastName}, {FirstName}";
还可以在只读属性中使用 expression-bodied 成员:(以下语句将会被编译成只读属性)
public string FullName => $"{FirstName} {LastName}";
// Expression-bodied get / set accessors.
public string Label {
get => label;
set => this.label = value ?? "Default label";
}
using static增强功能
using static
增强功能可用于导入单个类的静态方法。 以前,using
语句将所有类型导入命名空间中。
比如,我们只需要使用System
命名空间下的Math
类,其他的类我们并不使用,此时我们可以通过以下方式引入Math类
using static System.Math;
通过这种方式引入后,使用方式也与之前有一定的变化,如下:
// 之前的使用方式
Math.Abs(1 + 2.5);
// 使用 using static System.Math;之后的方式
Abs(1 + 2.5);
切记,这种引入方式只会引入该声明类中的静态方法。引入后的静态方法可当成全局函数使用,但其作用范围需要分为文件顶部引入和命名空间内部引入(参见温故之C# using注意事项)
Null 条件运算符?. ??
?.
运算符
在代码中,为了保证每个引用不会抛出NullException
异常,我们往往需要进行如下判断:
Feature feature = GetFeature();
if(tmpValue != null) {
Console.WriteLine(feature.ToString());
}
而有了 Null 条件运算符之后,我们的写法可简化为如下feature?.ToString()
:
Feature feature = GetFeature();
Console.WriteLine(feature?.ToString());
相信,此运算符在事件判断上更是会广泛使用,比如有Saved
事件,现在,我们可以以更加简洁且更加线程安全的方式访问了,如下
Saved?.Invoke(this, eventArgs);
??
运算符
此运算符可保证在没有合法值之时,为变量提供一个默认值。 在之前,是这样的:
string obj = null;
string res = string.Empty;
if (obj == null) {
obj = "this is default value";
}else {
res = obj;
}
Console.WriteLine(res);
而现在,是这样的:
string obj = null;
string res = obj ?? "this is default value";
Console.WriteLine(res);
看,现在是不是简洁了很多呢?另外,如果需要抛出异常,则可以按以下方式:
string obj = null;
string res = obj ?? throw new ArgumentNullException(paramName: nameof(obj), message: "must not be null");
Console.WriteLine(res);
字符串的格式化
在之前,我们格式化字符串方式如下:
string tmp = string.Format("{0} {1}", FirstName, LastName);
现在,我们可以以更加方便的方式处理:
string tmp = $"{FirstName} {LastName}";
不知道您是否发现了它的优势?除了比之前更加简洁之外,更重要的是,当需要格式化的参数很多(比如5个以上时),很容易将这些参数的顺序混淆,而现在,您所写的,就是它存在的顺序,减少了出错的概率(甚至根本不会出错)。
异常筛选器
异常筛选器是确定何时应该应用给定的 catch
子句的子句。如果用于异常筛选器的表达式计算结果为 true
,则 catch
子句将对异常执行正常处理。 如果表达式计算结果为 false
,则将跳过 catch
子句。使用方式如下:
public static async Task<string> MakeRequest() {
var client = new System.Net.Http.HttpClient();
var streamTask = client.GetStringAsync("https://localHost:10000");
try {
var responseText = await streamTask;
return responseText;
} catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
{
return "Site Moved";
}
}
nameof 表达式
nameof
表达式的计算结果为符号的名称。 每当需要变量、属性或成员字段的名称时,这是让工具正常运行的好办法。
nameof
的其中一个最常见的用途是提供引起异常的符号的名称,如下:
if (IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
这样写有个好处就是,假如我们需要使用重构工具重命名符号, 更改lastName
为firstName
,则会在 nameof
表达式中对其重命名。而字符串硬编码的方式则没有这一优势,很容易被忽略。
如果您写过WPF程序,那么您肯定使用过INotifyPropertyChanged
, 之前要实现属性更改的通知功能,实现方式如下:
public string LastName {
get { return lastName; }
set {
if (value != lastName) {
lastName = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LastName"));
}
}
}
private string lastName;
而现在,PropertyChangedEventArgs
的参数,可使用nameof(LastName)
:
public string LastName {
get { return lastName; }
set {
if (value != lastName) {
lastName = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(LastName)));
}
}
}
private string lastName;
Catch 和 Finally 块中的 Await
在 catch
表达式中使用 await
,这通常用于日志记录方案。如下:
public static async Task<string> MakeRequestAndLogFailures() {
await logMethodEntrance();
var client = new System.Net.Http.HttpClient();
var streamTask = client.GetStringAsync("https://localHost:10000");
try {
var responseText = await streamTask;
return responseText;
} catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301")) {
await logError("Recovered from redirect", e);
return "Site Moved";
} finally {
await logMethodExit();
client.Dispose();
}
}
不过,个人尚未发现此记录方式的优势,暂不推荐使用。一般地,在项目中需要记录日志,会采用单独的服务来处理日志,即有异常时,立即将异常信息发送给日志记录服务,而程序本身继续下一步。使用的较多的是采用Kafka
来进行日志的记录,关于Kafka
,您可以百度,如果还有疑惑,咨询我也可以。
至此,本节内容讲解完毕