What's new in C# 7.0
1.数字分隔符(digit separators )
数字分隔符使代码更具可读性。在声明变量时,可以将_添加到单独的数字中。编译器只删除_。以下代码片段在c#7中看起来更具可读性:
in c# 6
long n1 = 0x1234567890abcdef;
in c# 7
long n2 = 0x1234_5678_90ab_cdef;
in c# 7.2
long n2 = 0x_1234_5678_90ab_cdef;
2.二进制(binary literals )
c#7为二进制文件提供了一个新的文字。二进制文件只能包含va 0和1。现在,数字分隔符变得尤为重要
in c# 7
uint binary1 = 0b1111_0000_1010_0101_1111_0000_1010_0101;
3.expression-bodied 函数成员(expression-bodied members )
c#6允许表达式方法和属性。使用c#7,表达式主体可以与构造函数,析构函数,本地函数,属性访问器等一起使用。在这里,您可以看到c#6和c#7之间的属性访问器的区别:
in c# 6
private string _firstname; public string firstname { get { return _firstname; } set { set(ref _firstname, value); } }
in c# 7
private string _firstname; public string firstname { get => _firstname; set => set(ref _firstname, value); }
4.out 变量(out var)
在c#7之前,必须在使用之前声明out变量。使用c#7,代码减少了一行,因为变量可以声明
使用:
in c# 6
string n = "42"; int result; if (string.tryparse(n, out result) { console.writeline($"converting to a number was successful:{result}"); }
in c# 7
string n = "42"; if (string.tryparse(n, out var result) { console.writeline($"converting to a number was successful:{result}"); }
5.非尾随命名参数(non-trailing named arguments )
使用c#7.2,支持非尾随命名参数。有关详细信息,请参阅。
in c# 7.0
if (enum.tryparse(weekdayrecommendation.entity, ignorecase:true,result: out dayofweek weekday)) { reservation.weekday = weekday; }
in c# 7.2
if (enum.tryparse(weekdayrecommendation.entity, ignorecase:true,out dayofweek weekday)) { reservation.weekday = weekday; }
6.只读结构(readonly struct )
结构应该是只读的(有一些例外)。使用c#7.2,可以使用readonly修饰符声明结构,因此编译器会验证结构是否未更改。编译器也可以使用此保证不复制将其作为参数传递的结构,而是将其作为引用传递:
in c# 7.2
public readonly struct dimensions { public double length { get; } public double width { get; } public dimensions(double length, double width) { length = length; width = width; } public double diagonal => math.sqrt(length * length + width * width); }
7.in 修饰参数(in parameters )
c#7.2还允许带有参数的in修饰符。这可以保证传递的值类型不会改变,它可以通过引用传递以避免副本:
in c# 7.2
static void cantchange(in astruct s) { // s can't change }
8.private protected 访问修饰符
c#7.2添加了一个新的访问修饰符:private protected。访问修饰符protected internal允许访问该成员(如果已使用)来自同一程序集中的类型,或来自派生自该类的另一个程序集中的类型。对于private protected,如果类派生自基类并且在同一个程序集中,则只允许使用and而不是or访问。
使用c#7.1,定义了一个默认文字,与默认运算符相比,它允许更短的语法。默认运算符总是需要重复类型,现在不再需要了。
in c# 7.0
int x = default(int); immutablearray<int> arr = default(immutablearray<int>);
in c# 7.1
int x = default; immutablearray<int> arr = default;
10.本地函数(local functions )
在c#7之前,无法在方法中声明函数。你可以创建一个lambda表达式并调用它,如c#6代码片段所示:
in c# 6
public void somefunstuff() { func<int, int, int> add = (x, y) => x + y; int result = add(38, 4); console.writeline(result); }
使用c#7,可以在方法中声明本地函数。只能在方法范围内访问本地函数:
in c# 7
public void somefunstuff() { int add(int x, int y) => x + y; int result = add(38, 4); console.writeline(result); }
11.元组(tuples )
低于 c# 7.0 的版本中也提供元组,但它们效率低下且不具有语言支持。 这意味着元组元素只能作为 item1
和 item2
等引用。c# 7.0 引入了对元组的语言支持,可利用更有效的新元组类型向元组字段赋予语义名称。在c#7中,元组是语言的一部分,你可以定义成员的名字:
in c# 6
var t1 = tuple.create(42, "astring"); int i1 = t1.item1; string s1 = t1.item2;
in c# 7
var t1 = (n: 42, s: "magic"); int i1 = t1.n; string s1 = t1.s;
12.推断元组元素名称(inferred tuple names )
此功能是对 c# 7.0 中引入的元组功能一次小型增强。 在初始化元组时,许多时候,赋值操作右侧的变量名与用于元组元素的名称相同,元组元素的名称可通过在 c# 7.1 中初始化元组时使用的变量进行推断:
in c# 7.0
int count = 5; string label = "colors used in the map"; var pair = (count: count, label: label);
in c# 7.1
int count = 5; string label = "colors used in the map"; var pair = (count, label); // element names are "count" and "label"
13.析构元组(deconstructors )
在某些时候,你可能想要解包从方法返回的元组的成员。 可通过为元组中的每个值声明单独的变量来实现此目的。 这种解包操作称为析构元组
in c# 7
var p1 = new person("tom", "turbo"); (string firstname, string lastname) = p1;
14.模式匹配(pattern matching )
通过模式匹配,is运算符和switch语句增强了三种模式:const模式,类型模式和var模式。以下代码段显示
使用is运算符的模式。匹配的第一次检查与常量42匹配,第二次匹配检查person对象,第三次匹配检查具有var模式的每个对象。使用类型和var模式,可以为强类型访问声明变量:
in c# 7
public void patternmatchingwithisoperator(object o) { if (o is 42) { } if (o is person p) { } if (o is var v1) { } }
使用switch语句,可以对case子句使用相同的模式。如果模式匹配,您还可以声明要强类型的变量。您还可以使用何时在条件上过滤模式:
public void patternmatchingwithswitchstatement(object o) { swtich (o) { case 42: break; case person p when p.firstname == "katharina": break; case person p: break; case var v: break; } }
注:使用 when
关键字来指定模式的其他规则。
15.throw表达式(throw expressions )
抛出异常只能通过声明来实现;在表达中是不可能的。因此,当使用构造函数接收参数时,需要额外检查null以抛出argumentnullexception。使用c#7,可以在表达式中抛出异常,因此当左侧为空时,可以使用合并运算符抛出argumentnullexception
in c# 6
private readonly ibooksservice _booksservice; public bookcontroller(booksservice booksservice) { if (booksservice == null) { throw new argumentnullexception(nameof(b)); } _booksservice = booksservice; }
in c# 7
private readonly ibooksservice _booksservice; public bookcontroller(booksservice booksservice) { _booksservice = booksservice ?? throw new argumentnullexception(nameof(b)); }
16.异步main方法
在c#7.1之前,main方法总是需要声明为void类型。用c#7。1,main方法也可以是task类型,并使用async和await关键字:
in c# 7.0
static void main() { somemethodasync().wait(); }
in c# 7.1
async static task main() { await somemethodasync(); }
17.条件ref表达式
以下代码片段声明方法getnumber以返回对int的引用。这条路,调用者可以直接访问数组中的元素,并可以更改其内容:
in c# 7.0
int[] _numbers = { 3, 7, 11, 15, 21 }; public ref int getnumber(int index) { return ref _numbers[index]; }
in c# 7.2
变量 r
是对 arr
或 otherarr
中第一个值的引用。
ref var r = ref (arr != null ? ref arr[0] : ref otherarr[0]);
扩展:
1.使用c#7.2,可以将readonly修饰符添加到ref返回。调用者接收引用但不允许更改它:
in c# 7.2
int[] _numbers = { 3, 7, 11, 15, 21 }; public ref readonly int getnumber(int index) { return ref _numbers[index]; }
2.ref struct (在c#7.2之前,c#可以创建引用类型(类)和值类型(结构)。但是,当发生装箱时,结构也可以存储在堆上。用c#7.2,可以声明只允许在堆栈上使用的类型:ref struct)
in c# 7.2
ref struct onlyonthestack { }
c# 更多语法糖请参阅微软官方文档.
上一篇: JavaScript函数定义方法实例详解