C#最新功能(6.0、7.0)
<p>一直用C#开发程序,.NET的功能越来越多,变化也挺大的,从最初的封闭,到现在的开源,功能不断的增加,一直在进步。作为C#的强烈支持者,C#的变化,我不能不关注,这篇文章主要介绍,C#6.0和C#7.0增加的功能。C#的发展史和.NET以前的版本,请看C#和.NET版本,这边文章中有介绍。</p><h1>C# 6.0版</h1>
<h2>1. 静态导入</h2>
<p>using static 增强功能可用于导入单个类的静态方法。<br>例如:using static System.String;可以直接用String类中的静态方法,而不用string.XXXX</p>
<h2>2. 异常筛选器</h2>
<p>“异常筛选器”是确定何时执行catch中的程序, 如果用于异常筛选器的表达式计算结果为 true,则 catch 子句将对异常执行正常处理,如果表达式计算结果为 false,则将跳过 catch 子句。<br>例如:e.Message.Contains("test")为true执行,否则不执行</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span> (Exception e) when (e.Message.Contains(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)) {
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ce</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<h2>3. 只读自动属性、自动属性初始化表达式、Expression bodied 成员、字符串内插</h2>
<p>可以让属性初始化,仅仅初始化一次,这适用于方法和只读属性<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Class6
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> LastName { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> FirstName { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> FullName => $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{FirstName} {LastName}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ToString() => $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{FirstName},{LastName}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用</span>
Class6 test = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Class6();
test.LastName </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">jie</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
test.FirstName </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hua</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FullName:{test.FullName}, ToString:{test.ToString()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
test.LastName </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">xiao jie</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">FullName:{test.FullName}, ToString:{test.ToString()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">运行结果
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">FullName:hua jie, ToString:hua,jie
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">FullName:hua xiao jie, ToString:hua,xiao jie</span></pre>
</div>
<h2>4. Null 传播器</h2>
<p>Null 条件运算符使 null 检查更轻松、更流畅。 将成员访问 . 替换为 ?.<br>例如:var first = person?.FirstName; string test = null;string t = test?.ToString();<br>如果 Person 对象是 null,则将变量 first 赋值为 null,否则,将 FirstName 属性的值分配给该变量。【?.】的左侧使用任何表达式(包括方法调用)</p>
<h2>5. nameof 运算符</h2>
<p>nameof 表达式的计算结果为符号的名称,简单来说就是为了显示名称。<br>例如: string test = "测试"; Console.WriteLine($"{test} , nameof:{nameof(test)}");<br>结果:测试 , nameof:test</p>
<h2>6. 索引初始值设定项</h2>
<p>索引初始值设定项就是对索引初始化,可以像Cat cat = new Cat { Age = 10, Name = "Fluffy" };初始化值一样,只不过现在增加了索引的初始化</p>
<h2>7. Catch 和 Finally 块中的 Await</h2>
<p>C# 5 对于可放置 await 表达式的位置有若干限制。 使用 C# 6,现在可以在 catch 或 finally 表达式中使用 await。 <br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span> (Exception e) when (e.Message.Contains(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">test</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">await</span> Task.Run(() => { Console.WriteLine($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">await catch</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); });
}
</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">await</span> Task.Run(() => { Console.WriteLine($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">await finally</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); });
}</span></pre>
</div>
<h1>C#7.0</h1>
<h2>1. Out 变量</h2>
<p>现在可以在方法调用的参数列表中声明 out 变量,而不是编写单独的声明语句<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">int</span>.TryParse(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">123</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> result))
Console.WriteLine(result)</span></pre>
</div>
<h2>2. 元组</h2>
<p>需要包含多个数据元素的简单结构的方法,也不知道怎么解释,总之就是好用。<br>例如:</p>
<div class="cnblogs_code">
<pre>(<span style="color: rgba(0, 0, 255, 1)">string</span> Name, <span style="color: rgba(0, 0, 255, 1)">int</span> Age) user = (<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小红</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">);
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Name:{user.Name}, Age:{user.Age}</span><span style="color: rgba(128, 0, 0, 1)">"</span>);</pre>
</div>
<div class="cnblogs_code">
<pre>ValueTuple<<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>> valueTuple = <span style="color: rgba(0, 0, 255, 1)">new</span> ValueTuple<<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小红</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可以和Tuple对比学习</span>
Tuple<<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>> test = <span style="color: rgba(0, 0, 255, 1)">new</span> Tuple<<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小红</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">ValueTuple是值类型,Tuple是引用类型</span></pre>
</div>
<h2>3. 模式匹配</h2>
<p>模式匹配 是一种可让你对除对象类型以外的属性实现方法分派的功能,模式匹配支持 is 表达式和 switch 表达式。每个表达式都允许检查对象及其属性以确定该对象是否满足所寻求的模式,使用 when 关键字来指定模式的其他规则。is 表达式的增强功能, 可以针对值类型和引用类型进行测试。简单来说就是帮你测试类型。<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">string</span> test = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">123</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (test <span style="color: rgba(0, 0, 255, 1)">is</span> <span style="color: rgba(0, 0, 255, 1)">int</span> count) Console.WriteLine(count);</pre>
</div>
<p>上面的例子会提示int类型的模式无法处理string类型的表达式。</p>
<h2>4. 本地函数</h2>
<p>许多类的设计都包括仅从一个位置调用的方法。 这些额外的私有方法使每个方法保持小且集中。 本地函数使你能够在另一个方法的上下文内声明方法 。 本地函数使得类的阅读者更容易看到本地方法仅从声明它的上下文中调用。简单来说就是方法中写方法。<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> Test()
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span> count = Add(<span style="color: rgba(128, 0, 128, 1)">12</span>, <span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> count;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> Add(<span style="color: rgba(0, 0, 255, 1)">int</span> a, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> b)
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
}</span></pre>
</div>
<h2>5. Ref 局部变量和返回结果</h2>
<p>此功能允许使用并返回对变量的引用的算法,这些变量在其他位置定义。<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> NumberStore
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span>[] numbers = { <span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(128, 0, 128, 1)">3</span>, <span style="color: rgba(128, 0, 128, 1)">7</span>, <span style="color: rgba(128, 0, 128, 1)">15</span>, <span style="color: rgba(128, 0, 128, 1)">31</span>, <span style="color: rgba(128, 0, 128, 1)">63</span>, <span style="color: rgba(128, 0, 128, 1)">127</span>, <span style="color: rgba(128, 0, 128, 1)">255</span>, <span style="color: rgba(128, 0, 128, 1)">511</span>, <span style="color: rgba(128, 0, 128, 1)">1023</span><span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">ref</span> <span style="color: rgba(0, 0, 255, 1)">int</span> FindNumber(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> target)
{
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> ctr = <span style="color: rgba(128, 0, 128, 1)">0</span>; ctr < numbers.Length; ctr++<span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (numbers >=<span style="color: rgba(0, 0, 0, 1)"> target)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)"> numbers;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">ref</span> numbers[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">];
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">string</span> ToString() => <span style="color: rgba(0, 0, 255, 1)">string</span>.Join(<span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, numbers);
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> store = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> NumberStore();
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Original sequence: {store.ToString()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">int</span> number = <span style="color: rgba(128, 0, 128, 1)">16</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">ref</span> <span style="color: rgba(0, 0, 255, 1)">var</span> value = <span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)"> store.FindNumber(number);
value </span>*= <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">New sequence: {store.ToString()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> The example displays the following output:
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Original sequence: 1 3 7 15 31 63 127 255 511 1023
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> New sequence: 1 3 7 15 62 63 127 255 511 1023</span></pre>
</div>
<p>31变成62了,对象中的数组值改变了,这个功能觉得要慎用。</p>
<h2>6. 弃元</h2>
<p>通常,在进行元组解构或使用 out 参数调用方法时,必须定义一个其值无关紧要且你不打算使用的变量。 为处理此情况,C# 增添了对弃元的支持 。 弃元是一个名为 _(下划线字符)的只写变量,可向单个变量赋予要放弃的所有值。 弃元类似于未赋值的变量;不可在代码中使用弃元(赋值语句除外)。简单来说就是放弃不需要的值。<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> (<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">double</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>) Test(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> name)
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (name, <span style="color: rgba(128, 0, 128, 1)">1.234</span>, <span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> (name, _, age) = Test(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">测试</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">测试弃元: Name:{name}, Age:{age}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">运行结果:测试弃元: Name:测试, Age:20</span></pre>
</div>
<h2>7. 二进制文本和数字分隔符</h2>
<p>误读的数值常量可能使第一次阅读代码时更难理解。 位掩码或其他符号值容易产生误解。 C# 7.0 包括两项新功能,可用于以最可读的方式写入数字来用于预期用途:二进制文本和数字分隔符 。简单来说就是可以把数字分割等<br>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">int</span> test =<span style="color: rgba(0, 0, 0, 1)"> 1_123_21;
Console.WriteLine(test);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">结果 112321</span></pre>
</div>
<h2>8. 引发表达式</h2>
<p>throw 始终是一个语句。 因为 throw 是一个语句而非表达式,所以在某些 C# 构造中无法使用它。<br>例如:string test = false ? "" : throw new Exception("必须是字符串,否则报错。");</p>
<h2>9. 增加异步返回类型ValueTask</h2>
<p>异步方法返回类型不限于 Task、Task<T> 和 void,可以是ValueTask<int>,可避免在性能上分配 Task。<br>可以查看 【C#中await/async闲说】,这篇文章对异步性能进行了说明,对ValueTask的使用进行了说明</p>
<p> </p>
<h2>其他的版本的基础功能</h2>
<p>1. C#高级功能(四)扩展方法和索引</p>
<p>2. C#高级功能(三)Action、Func,Tuple</p>
<p>3. C#高级功能(二)LINQ 和Enumerable类</p>
<p>4. C#高级功能(一)Lambda 表达式</p>
<p>5. C#中泛型的解释(object,list,var,dynamic的区别)</p>
<p>6. C#中委托</p>
<p>7. C#和.NET版本对比</p><br><br>
来源:https://www.cnblogs.com/zhao123/p/11098078.html
頁:
[1]