天涯相随 發表於 2020-11-9 18:14:00

说说 C# 9 新特性的实际运用

<p>你一定会好奇:“老周,你去哪开飞机了?这么久没写博客了。”</p>
<p>老周:“我买不起飞机,开了个铁矿,挖了一年半的石头。谁知铁矿垮了,压死了几条蜈蚣,什么也没挖着。”</p>
<p>所以,这么丢死人的事,还是不要提了,爷爷从小教导我做人要低调……</p>
<p>&nbsp;</p>
<p>一转眼,.NET 5 要来了,同时也带来了 C# 9。遥想当年,老周刚接触 .NET 1.1 的时候,才刚上大学;如今已经过去13年了。岁月是把水果刀,从来不饶人啊。</p>
<p>老周很少去写诸如“XXX新特性”之类的文章,总觉得没啥用处。不过,针对 C# 9,老周想说一点什么。</p>
<p>好,在开始之前,老周再次强调一下:这些语言新特性的东西,<span style="font-size: 18px"><strong>你千万不要特意去学习,千万不要,不要,不要</strong></span>,重要的事情讲四遍!这些玩意儿你只要看看官方给的说明,刷一遍就能掌握了(刷这个比刷抖音有意义多了),不用去学的。如果你连这些东东也要学习成本的话,我只想说句好唱不好听的话——<span style="font-size: 14pt"><strong>你的学习能力真的值得怀疑</strong></span>。</p>
<p>&nbsp;</p>
<p>好了,下面开始表演。</p>
<h2>第一出:record 类型</h2>
<p>record ,我还是用原词吧,我知道有翻译为“记录类型”的说法。只是,只是,老周老觉得这不太好听,可是老周也找不出更好的词语,还是用回 record吧。</p>
<p>record 是<span style="text-decoration: underline"><strong>引用类型</strong></span>,跟 class 很像(确实差不多)。那么,用人民群众都熟悉的 class 不香吗,为何要新增个 record 呢?答:为了数据比较的便捷。</p>
<p>不明白?没事,往下看。最近有一位热心邻居送了老周一只宠物:</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)"> Cat
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Nick { <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> Name { <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)">int</span> Age { <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></pre>
</div>
<p>这只新宠物可不简单,一顶一的高级吃货。鱼肉、猪肉、鸡腿、饼干、豆腐、面包、水果、面条、小麦、飞蛾……反正,只要它能塞进嘴里的,它都吃。</p>
<p>接下来,我们 new 两个宠物实例。</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 两个实例描述的是同一只猫</span>
            Cat pet1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Cat
            {
                Nick </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(0, 0, 0, 1)">,
                Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Jack</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                Age </span>= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">
            };
            Cat pet2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Cat
            {
                Nick </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(0, 0, 0, 1)">,
                Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Jack</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                Age </span>= <span style="color: rgba(128, 0, 128, 1)">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>
            Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">同一只?{0}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, pet1 == pet2);</pre>
</div>
<p>其实,两个实例描述的都是我家的乖乖。可是,输出的是:</p>
<div class="cnblogs_code">
<pre>同一只?False</pre>
</div>
<p>这是因为,在相等比较时,人家关心的类型引用——引用的是否为同一个实例。但是,在数据处理方案中,我们更关注对象中的字段/属性是否相等,即内容比较。</p>
<p>现在,把 Cat 的声明改为 record 类型。</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> record Cat
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Nick { <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> Name { <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)">int</span> Age { <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></pre>
</div>
<p>然后同样用上面的 pet1 和 pet2 实例进行相等比较,得到预期的结果:</p>
<div class="cnblogs_code">
<pre>同一只?True</pre>
</div>
<p>&nbsp;</p>
<p>record 类型让你省去了重写相等比较(重写 Equals、GetHashCode 等方法或重载运算符)的逻辑。</p>
<p>实际上,代码在编译后 record 类型也是一个类,但自动实现了成员相等比较的逻辑。以前你要手动去折腾的事现在全交给编译器去干。</p>
<p>假如,有一个 User 类型,用于表示用户信息(包括用户名、密码),然后这个 User 类型在数据处理方案中可能会产生N多个实例。例如你根据条件从EF模型中筛选出一个 User 实例 A,根据用户输入的登录名和密码产生了 User 实例 B。为了验证用户输入的登录信息是否正确,如果 User 是 class,你可能要这样判断:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span>(A.UserName == B.UserName &amp;&amp; A.Password ==<span style="color: rgba(0, 0, 0, 1)"> B.Password)
{
    ..................
}</span></pre>
</div>
<p>但要是你把 User 定义为 record 类型,那么,一句话的工夫:</p>
<div class="cnblogs_code">
<pre>A == B</pre>
</div>
<p>&nbsp;</p>
<h2>第二出:模式匹配(Pattern Matching)</h2>
<p>"模式匹配"这个翻译感觉怪怪滴,老周还没想出什么更好的词语。模式匹配并不是什么神奇的东西,它只是在对变量值进行检测时的扩展行为。以前,老感觉C++/C# 的 switch 语句不够强大,因为传统的用法里面,每个 case 子句只能比较单个常量值。比如</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">int</span> 考试成绩 = <span style="color: rgba(128, 0, 128, 1)">85</span><span style="color: rgba(0, 0, 0, 1)">;

            </span><span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (考试成绩)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 128, 1)">10</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)">才考这么点破分啊</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 128, 1)">50</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)">还差一点,就合格了</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 128, 1)">85</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)">真是秀</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 128, 1)">90</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)">奇迹发生</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
            }</span></pre>
</div>
<p>我幻想着,要是能像下面这样写就好了:</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (考试成绩)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 128, 1)">0</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)">缺考?</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt; <span style="color: rgba(128, 0, 128, 1)">0</span> &amp;&amp; &lt;= <span style="color: rgba(128, 0, 128, 1)">30</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)">太烂了</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt; <span style="color: rgba(128, 0, 128, 1)">30</span> &amp;&amp; &lt; <span style="color: rgba(128, 0, 128, 1)">60</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)">还是不行</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt;= <span style="color: rgba(128, 0, 128, 1)">60</span> &amp;&amp; &lt; <span style="color: rgba(128, 0, 128, 1)">80</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)">还得努力</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt;= <span style="color: rgba(128, 0, 128, 1)">80</span> &amp;&amp; &lt; <span style="color: rgba(128, 0, 128, 1)">90</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)">秀儿,真优秀</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt;= <span style="color: rgba(128, 0, 128, 1)">90</span> &amp;&amp; &lt;= <span style="color: rgba(128, 0, 128, 1)">100</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)">不错,奇迹</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
            }</span></pre>
</div>
<p>&nbsp;</p>
<p>等了很多年很多年(“千年等一回,等……”)以后,终于可以实现了。</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (考试成绩)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> <span style="color: rgba(128, 0, 128, 1)">0</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)">缺考?</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt; <span style="color: rgba(128, 0, 128, 1)">0</span> and &lt;= <span style="color: rgba(128, 0, 128, 1)">30</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)">太烂了</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt; <span style="color: rgba(128, 0, 128, 1)">30</span> and &lt; <span style="color: rgba(128, 0, 128, 1)">60</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)">还是不行</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt;= <span style="color: rgba(128, 0, 128, 1)">60</span> and &lt; <span style="color: rgba(128, 0, 128, 1)">80</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)">还得努力</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt;= <span style="color: rgba(128, 0, 128, 1)">80</span> and &lt; <span style="color: rgba(128, 0, 128, 1)">90</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)">秀儿,真优秀</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> &gt;= <span style="color: rgba(128, 0, 128, 1)">90</span> and &lt;= <span style="color: rgba(128, 0, 128, 1)">100</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)">不错,奇迹</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)">break</span><span style="color: rgba(0, 0, 0, 1)">;
            }</span></pre>
</div>
<p>哟西,真香。</p>
<p>&nbsp;</p>
<p>有时候,不仅要检测对象的值,还得深入到其成员。比如下面这个例子,Order类表示一条订单信息。</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)"> Order
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> ID { <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> Company { <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> ContactName { <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)">float</span> Qty { <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)">decimal</span> UP { <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> DateTime Date { <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></pre>
</div>
<p>前不久,公司接到一笔Order,做成了收益应该不错。</p>
<div class="cnblogs_code">
<pre>            Order od = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Order
            {
                ID </span>= <span style="color: rgba(128, 0, 128, 1)">11</span><span style="color: rgba(0, 0, 0, 1)">,
                Company </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(0, 0, 0, 1)">,
                ContactName </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(0, 0, 0, 1)">,
                Qty </span>= <span style="color: rgba(128, 0, 128, 1)">425.12f</span><span style="color: rgba(0, 0, 0, 1)">,
                UP </span>= <span style="color: rgba(128, 0, 128, 1)">1000.55M</span><span style="color: rgba(0, 0, 0, 1)">,
                Date </span>= <span style="color: rgba(0, 0, 255, 1)">new</span>(<span style="color: rgba(128, 0, 128, 1)">2020</span>, <span style="color: rgba(128, 0, 128, 1)">10</span>, <span style="color: rgba(128, 0, 128, 1)">27</span><span style="color: rgba(0, 0, 0, 1)">)
            };</span></pre>
</div>
<p>假如我要在变量 od 上做 switch,看看,就这样:</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (od)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> { Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 1000f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> { Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 500f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> { Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 100f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
            }</span></pre>
</div>
<p>咦?这,这是什么鬼?莫惊莫惊,这不是鬼。它的意思是判断 Qty 属性的值,如果订单货量大于 100 就输出“订单量不错”;要是订单货量大于 1000,那就输出“发财了,发财了”。</p>
<p>但你会说,这对大括号怎么来的呢?还记得这种 LINQ 的写法吗?</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">from</span> x <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> ...
      </span><span style="color: rgba(0, 0, 255, 1)">where</span><span style="color: rgba(0, 0, 0, 1)"> x.A ...
      </span><span style="color: rgba(0, 0, 255, 1)">select</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> {
            Prop1 </span>=<span style="color: rgba(0, 0, 0, 1)"> ...,
            Prop2 </span>=<span style="color: rgba(0, 0, 0, 1)"> ...,
            ................
      }            </span></pre>
</div>
<p>new { ... } 是匿名类型实例,那如果是非匿名类型呢,看看前面的 Cat 实例初始化。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">   Cat {
         ..........
   }</span></pre>
</div>
<p>这就对了,这对大括号就是构造某实例的成员值用的,所以,上面的 switch 语句其实是这样写的:</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (od)
            {
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> Order{ Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 1000f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> Order{ Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 500f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">case</span> Order{ Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 100f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
            }</span></pre>
</div>
<p>Order{ ... } 就是匹配一个 Order 对象实例,并且它的 Qty 属性要符合 ... 条件。由于变量 od 始终就是 Order 类型,所以,case 子句中的 Order 就省略了,变成</p>
<div class="cnblogs_code">
<pre>                <span style="color: rgba(0, 0, 255, 1)">case</span> { Qty: &gt;<span style="color: rgba(0, 0, 0, 1)"> 1000f }:
                  Console.WriteLine(</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(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">break</span>;</pre>
</div>
<p>如果出现多个属性,则表示为多个属性设定匹配条件,它们之间是“且”的关系。比如</p>
<div class="cnblogs_code">
<pre>                <span style="color: rgba(0, 0, 255, 1)">case</span> { Qty: &gt; 100f, Company: not <span style="color: rgba(0, 0, 255, 1)">null</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)">订单量不错</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)">break</span>;</pre>
</div>
<p>猜猜啥意思?这个是可以“望文生义”的,Qty 属性的值要大于 100,并且 Company 属性的值不能为 null。不为 null 的写法是 not null,不要写成 !null,因为这样太难看了。</p>
<p>&nbsp;</p>
<p>如果你的代码分支较少,你可以用 if 语句的,只是得配合 is 运算符。</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">if</span> (od <span style="color: rgba(0, 0, 255, 1)">is</span> { UP: &lt;<span style="color: rgba(0, 0, 0, 1)"> 3000M })
            {
                Console.WriteLine(</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(0, 0, 0, 1)">);
            }</span></pre>
</div>
<p>但是,这个写法目前有局限性,它只能用常量值来做判断,你要是这样写就会报错。</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">if</span> (od <span style="color: rgba(0, 0, 255, 1)">is</span> { Date: &lt;<span style="color: rgba(0, 0, 0, 1)"> DateTime.Now })
            {
                ................
            }</span></pre>
</div>
<p>DateTime.Now 不是常量值,上面代码无法通过编译。</p>
<p>&nbsp;</p>
<p>is 运算符以前是用来匹配类型的,上述的用法是它的语法扩展。</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">object</span> n = <span style="color: rgba(128, 0, 128, 1)">5000000L</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">if</span>(n <span style="color: rgba(0, 0, 255, 1)">is</span> <span style="color: rgba(0, 0, 255, 1)">long</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)">它是个长整型</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            }</span></pre>
</div>
<p>进化之后的 is 运算符也可以这样用:</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">object</span> n = <span style="color: rgba(128, 0, 128, 1)">5000000L</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">if</span>(n <span style="color: rgba(0, 0, 255, 1)">is</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> x)
            {
                Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">它是个长整型,存放的值是:{0}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, x);
            }</span></pre>
</div>
<p>如果你在 if 语句内要使用 n 的值,就可以顺便转为 long 类型并赋值给变量 x,这样就一步到位,不必再去写一句 long x = (long)n 。</p>
<p>&nbsp;</p>
<p>如果 switch... 语句在判断之后需要返回一个值,还可以把它变成表达式来用。咱们把前面的 Order 例子改一下。</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 0, 255, 1)">string</span> message = od <span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)">
            {
                { Qty: </span>&gt; 1000f }    =&gt; <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)">,
                { Qty: </span>&gt; 500f }   =&gt; <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)">,
                { Qty: </span>&gt; 100f }   =&gt; <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)">,
                _                   </span>=&gt; <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(message);</span></pre>
</div>
<p>这时候你得注意:</p>
<p>1)switch 现在是表达式,不是语句块,所以最后大括号右边的分号不能少;</p>
<p>2)因为 switch 成了表达式,就不能用 case 子句了,所以直接用具体的内容来匹配;</p>
<p>3)最后返回“未知”的那个下划线(_),也就是所谓的“弃婴”,哦不,是“弃元”,就是虽然赋了值但不需要使用的变量,可以直接丢掉。这里就相当于 switch 语句块中的 default 子句,当前面所有条件都不能匹配时,就返回“未知”。</p>
<p>&nbsp;</p>
<h2>第三出:属性的 init 访问器</h2>
<p>要首先得知道,这个 init 只用于只读属性的初始化阶段,对于可读可写的属性,和以前一样,直接 get; set; 即可。</p>
<p>有人说这个 init 不知干啥用,那好,咱们先不说它,先来看看 C# 前些版本中新增的属性初始化语句。</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)"> Dog
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> No { <span style="color: rgba(0, 0, 255, 1)">get</span>; } = <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)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; } = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">no name</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)">int</span> Age { <span style="color: rgba(0, 0, 255, 1)">get</span>; } = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
    }</span></pre>
</div>
<p>你看,这样就可以给属性分配初始值了,那还要 init 干吗呢?</p>
<p>好,我给你制造一个问题——我要是这样初始化 Dog 类的属性,你试试看。</p>
<div class="cnblogs_code">
<pre>            Dog x = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Dog
            {
                No </span>= <span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">,
                Name </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(0, 0, 0, 1)">,
                Age </span>= <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">
            };</span></pre>
</div>
<p>试一下,编译会出错吧。</p>
<p><img src="https://img2020.cnblogs.com/blog/367389/202011/367389-20201109180014044-706088802.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>有些情况,你可以在属性定义阶段分配初始值,但有些时候,你必须要在代码中初始化。在过去,我们会通过定义带参数的构造函数来解决。</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)"> Dog
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> No { <span style="color: rgba(0, 0, 255, 1)">get</span>; } = <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)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; } = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">no name</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)">int</span> Age { <span style="color: rgba(0, 0, 255, 1)">get</span>; } = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;

      </span><em><strong><span style="color: rgba(0, 0, 255, 1)">public</span> Dog(<span style="color: rgba(0, 0, 255, 1)">int</span> no, <span style="color: rgba(0, 0, 255, 1)">string</span> name, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> age)
      {
            No </span>=<span style="color: rgba(0, 0, 0, 1)"> no;
            Name </span>=<span style="color: rgba(0, 0, 0, 1)"> name;
            Age </span>=</strong></em><span style="color: rgba(0, 0, 0, 1)"><em><strong> age;
      }</strong></em>
    }</span></pre>
</div>
<p>然后,这样初始化。</p>
<div class="cnblogs_code">
<pre>   Dog x = <span style="color: rgba(0, 0, 255, 1)">new</span>(<span style="color: rgba(128, 0, 128, 1)">1001</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)">4</span>);</pre>
</div>
<p>&nbsp;</p>
<p>可是,这样做的装逼指数依然不够高,你总不能每个类都来这一招吧,虽然不怎么辛苦,但每个类都得去写一个构造函数,不利落。</p>
<p>于是,init 访问器用得上了,咱们把 Dog 类改改。</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)"> Dog
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> No { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> Age { <span style="color: rgba(0, 0, 255, 1)">get</span><span style="color: rgba(0, 0, 0, 1)">; init; }
    }</span></pre>
</div>
<p>你不用再去写带参数的构造函数了,实例化时直接为属性赋值。</p>
<div class="cnblogs_code">
<pre>            Dog x = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Dog
            {
                No </span>= 100<span style="color: rgba(0, 0, 0, 1)">,
                Name </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(0, 0, 0, 1)">,
                Age </span>= <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">
            };</span></pre>
</div>
<p>这样一来,这些只读属性都有默认的初始值了。</p>
<p>当然,这个赋值只在初始化过程中有效,初始化之后你再想改属性的值,没门!</p>
<div class="cnblogs_code">
<pre>            x.Name = <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, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误</span>
            x.Age = <span style="color: rgba(128, 0, 128, 1)">10</span>;       <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误</span></pre>
</div>
<p>&nbsp;</p>
<p>嗯,好了,以上就是老周对 C# 9 新特性用法的一些不成文的阐述。看完后你就别说难了。</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/tcjiaan/p/13947928.html
頁: [1]
查看完整版本: 说说 C# 9 新特性的实际运用