c# 7.0 新特性

系列文章


内联申明out变量

在7.0以前我们遇到使用带有out参数的方法时需要单独申明这个变量,在7.0以后可以内联的使用out变量

<code>Int32 result;
Int32.TryParse(input, out result); // use out variable in c#6.0


Int32.TryParse(input, out Int32 result); // use out variable in c#7.0+
Int32.TryParse(input, out var result); // use implicitly out variable in c#7.0+/<code>

元组

C# 为用于说明设计意图的类和结构提供了丰富的语法。但是有时候这种语法很笨重;在7.0以前c#也提供元组,当不是语言级别的支持

元组是包含多个字段以表示数据成员的轻量级数据结构。 这些字段没有经过验证,并且你无法定义自己的方法

<code>(string Alpha, string Beta) namedLetters = ("a", "b");   // use Tuples in c#7.0+
Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}"); /<code>

弃元

在使用具有out参数的方法调用时,或者元组析构时,有时候必须为了不需要使用的参数或者元素定义一个变量,在c#7.0可以通过使用名为 _(下划线) 的符号来放弃指定位置的值;

弃元可以使用在1)元素或用户自定义类型解构,2)调用具有out参数的方法,3)is或者swith的模式匹配语句中,4)赋值语句的左值

<code>在对元组或用户定义的类型进行解构时。
在使用 out 参数调用方法时。
在使用 is 和 switch 语句匹配操作的模式中。
在要将某赋值的值显式标识为弃元时用作独立标识符。/<code>

模式匹配

模式匹配支持 is 表达式和 switch 表达式。

<code>// is 增强的模式匹配
if (input is int count) // 经过测试后将值赋给后面类型正确的新变量
sum += count;

// switch 模式匹配
public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int sum = 0;
foreach (var i in sequence)
{
switch (i)
{
case 0: // 是常见的常量模式。
break;
case IEnumerable childSequence: //一种类型模式
{
foreach(var item in childSequence)

sum += (item > 0) ? item : 0;
break;
}
case int n when n > 0: // 具有附加 when 条件的类型模式
sum += n;
break;
case null: // null 模式
throw new NullReferenceException("Null found in sequence");
default: // 常见的默认事例
throw new InvalidOperationException("Unrecognized type");
}
}
return sum;
}
/<object>/<code>

ref 局部变量和返回结果

允许返回和使用在其它地方定义的引用变量

<code>// Demo 在一个矩阵中查找指定元素并返回其引用
public static ref int Find(int[,] matrix, Func predicate)
{
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (predicate(matrix[i, j]))
return ref matrix[i, j];
throw new InvalidOperationException("Not found");
}
/<code>

本地函数

许多类的设计都包括仅从一个位置调用的方法。 这些额外的私有方法使每个方法保持小且集中。

<code>// Demo 通过本地函数使得方法中参数检验肯执行分离
public static IEnumerable<char> 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<char> alphabetSubsetImplementation()
{
for (var c = start; c < end; c++)
yield return c;
}
}/<char>/<char>/<code>

expression-bodied 成员

在c# 6.0中只为只读属性和成员函数引入了表达式体,在c# 7.0 扩展到可在属性,索引器,终结器,get,set访问器使用

<code>// Expression-bodied constructor
public ExpressionMembersExample(string label) => this.Label = label;

// Expression-bodied finalizer
~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");

private string label;

// Expression-bodied get / set accessors.
public string Label
{
get => label;
set => this.label = value ?? "Default label";
}/<code>

throw 表达式

在c# 7.0以前 throw 不可以在三元表达式 ?? 表达式 以及表达式体中出现,下面演示在三元表达式中使用throw表达式

<code>// use throw expression in condational opeartor, you must appear in an if/else statement.1
string arg = args.Length >= 1 ? args[0] : throw new ArgumentException("You must supply an argument");/<code>

通用的异步返回类型

从异步方法返回 Task 对象可能在某些路径中导致性能瓶颈。 Task 是引用类型,因此使用它意味着分配对象。 如果使用 async 修饰符声明的方法返回缓存结果或以同步方式完成,那么额外的分配在代码的性能关键部分可能要耗费相当长的时间。 如果这些分配发生在紧凑循环中,则成本会变高。

新的特性去除了异步方法必须从Task,Task, void 返回,只要返回值具有可以访问的GetAwaiter方法即可,官方实例

<code>public async ValueTask Func()
{
await Task.Delay(100);
return 5;
}
/<code>

数字文本语法改进

直接上代码演示,看效果

<code>public const int Sixteen =   0b0001_0000;
public const int ThirtyTwo = 0b0010_0000;
public const int OneMillion = 100_0000;
public const int ThreeBillion = 3_0000_0000;
public const double AvogadroConstant = 6.012_140_857_747_474e23;/<code>

通过在数字中添加下划线来增加可读性


分享到:


相關文章: