值得思考的示例:
var s1 = $"hello, {name}";
IFormattable s2 = $"Hello, {name}";
FormattableString s3 = $"Hello, {name}";
四、NULL 条件运算符
用于在执行成员访问 (?.) 或索引 (?[) 操作之前,测试是否存在 NULL 值。 这些运算符可让你编写更少的代码来检查 null 值。
string name = null;
Console.WriteLine($"1:{name?.Length}");
name = "Fanguzai";
Console.WriteLine($"2:{name?.Length}");
Console.WriteLine($"3: {name?[0]}");

我们来看看另一种用途,可以使用非常少的代码以线程安全的方式调用委托:
//普通的委托调用
Func<int> func = () => 0;
if (func!=null)
{
func();
}
//简化调用
func?.Invoke();
五、catch 和 finally 块中使用 await
现在可以在 catch 和 finally 块中使用 await 了。

用法:
async Task Test()
{
var wc = new WebClient();
try
{
await wc.DownloadDataTaskAsync("");
}
catch (Exception)
{
await wc.DownloadDataTaskAsync(""); //OK
}
finally
{
await wc.DownloadDataTaskAsync(""); //OK
}
}
六、自动实现的属性
现在可以通过与初始化字段相似的方式来初始化自动属性。当属性访问器中不需要任何其他逻辑时,自动实现的属性会使属性声明更加简洁。
class MyClass
{
public string Name { get; set; } = "Fanguzai";
}
static void Main(string[] args)
{
var myClass=new MyClass();
Console.WriteLine(myClass.Name);
Console.Read();
}

其实就是 Name 提供默认的返回值,也可以理解为这样写:
class MyClass
{
public string Name { get; set; }
public MyClass()
{
Name = "Fanguzai";
}
}
七、只有 getter 的自动属性
现在可以定义只读自动属性,而不必使用完整属性语法定义属性。可以在声明属性的位置或类型的构造函数中初始化属性。
class Person
{
//新语法
private string Name { get; } = "Fanguzai"; //不用带上 private set;
//旧语法
public int Age { get; private set; } ;
}
八、具有表达式主体的函数成员
可以采用与用于 lambda 表达式相同的轻量语法,声明具有代码表达式主体的成员。具有立即仅返回表达式结果,或单个语句作为方法主题的方法定义很常见。 以下是使用 => 定义此类方法的语法快捷方式:










