自动属性默认初始化
使用方法:
public string Name { get; set; } = "Hello World";
编译器生成代码:
public class Customer
{
[CompilerGenerated]
private string kBackingField = "<span style="color: #993300;">hello world</span>";
public Customer()
{
this.kBackingField = "hello world";
}
public string Name
{
[CompilerGenerated]
get
{
return this.<Name>k__BackingField;
}
[CompilerGenerated]
set
{
this.<Name>k__BackingField = value;
}
}
}
从生成代码中可以看出编译器是在实例化构造函数时,初始化属性信息的。
自动只读属性默认初始化
使用方法:
public string Name1 {get;} = "hello world";
编译器生成代码:
public class Customer
{
[CompilerGenerated]
private string kBackingField = "hello world";
public Customer()
{
this.kBackingField = "hello world";
}
public string Name
{
[CompilerGenerated]
get
{
return this.<Name>k__BackingField;
}
[CompilerGenerated]
set
{
this.<Name>k__BackingField = value;
}
}
}
从生成的代码中也可以看到编译器是在实例化构造函数时,初始化属性信息的。
表达式为主体的函数
使用方法:
Body Get(int x, int y) => new Body(1 + x, 2 + y);
编译器生成代码:
private Program.Body Get(int x, int y)
{
return new Program.Body(1+x, 2+y);
}
从生成的代码中可以看到简化了单选方法的编写,省去写大括号的功夫。
同时也支持没有返回值的写法:
void OutPut(int x, int y) => Console.WriteLine("hello, world");
也支持异步函数的编写:
async void OutPut(int x, int y) => await new Task(() => Console.WriteLine("hello world"));
表达式为主体的属性(赋值)
使用方法:
public string Name2 => "hello world";
编译器生成代码如下:
public string Name2
{
get { return "hello world"; }
}
编译器只生成了个只读属性
静态类导入
这个比较容易理解,就是一次性导入某类型的所有静态成员,然后在后面的代码中直接使用,比如:
using static System.Console;
class Program
{
static void Main(string[] args}
{
WriteLine("hello world");
}
}
Null 条件运算符
使用方法:
Customer cust = new Customer();
if (cust != null)
{
string name = cust.Name;
}
等同于:
Customer cust = new Customer();
string name = cust?.Name;
可以和??组合起来使用:
if (customer?.Face()?? false)
还可以2个一起用
int? Length = customer?.Name?.Length;
这个语法糖目的是在对象使用前检查是否为null,如果对象为空,则赋值给变量为宿舍,所以例子中需要一个可以为空的Int类型,即int?
如果对象不为空,则调用对象的成员取舍,并赋值给变量
字符串格式化
在下面的例子中,String.Format 有些不方便的地方是:必须输入“String.Format", 使用{0}点位符,必须按顺序来格式化,这点比较容易出错:
var s = String.Format("{0} is {1} year old", p.Name, p.Age);
新的语法糖可以这么使用:
var s = $"{p.Name} is {p.Age} year old";
比较有趣的是,新格式方法还支持任何表达式的直接赋值:
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";
索引的初始化
使用List时,虽然可以通过下面的方式书写,可以编译通过,但还是会抛异常,使用方法:
var numbers = new List<string> { [7] = "seven", [9] ="nine", [13] ="thirteen"};
编译器生成代码:
List list = new List();
list[7] = "seven";
list[9] = "nine";
list[13] = "thirteen";
Dictionary 可以执行,因为二者内部索引机制不一样:
var numbers = new Dictionary<int, string> {[7] = "seven",[9] = "nine",[13] = "thirteen";
异常过滤器 when
使用方法:
try
{
throw new ArgumentException("string error");
}
catch (ArgumentException e) when (myfilter(e))
{
Console.WriteLine(e.Message);
}
static bool myfilter(ArgumentException e)
{
return false;
}
When语法作用是:在进入到catch之前、验证when括号里myfilter方法返回的bool,如果返回true继续运行,false不走catch直接抛出异常。
使用这个filter可以更好的判断一个错误是继续处理还是重新抛出去。按照以前的做法,在catch块内如需再次抛出去,需要重新throw出去,这时的错误源是捕捉后在抛的,而不是原先的,有了when语法就可以直接定位到错误源。
nameof表达式
有时候会需要程序中一些成员的字符串名称,比如抛出ArgumentNullException异常的时候,想知道ArgumentNullException类型的字符串名称,这时候就可以用nameof获取字符
串“ArgumentNullException”。现在做法都是手动复制一下,但重构改名的时候容易忘记变更字符串,使用nameof就可以避免了。
string name = "";
Console.WriteLine(nameof(name));
网友评论