C# 9 新特性 —— 增强的 foreach
<h1 id="c-9-新特性--增强的-foreach">C# 9 新特性 —— 增强的 <code>foreach</code></h1><h2 id="intro">Intro</h2>
<p>在 C# 9 中增强了 <code>foreach</code> 的使用,使得一切对象都有 <code>foreach</code> 的可能</p>
<p>我们来看一段代码,这里我们试图遍历一个 <code>int</code> 类型的值</p>
<p><img src="https://img2020.cnblogs.com/blog/489462/202012/489462-20201228233628043-498856471.png" alt="" loading="lazy"></p>
<p>思考一下,我们可以怎么做使得上面的代码编译通过呢?</p>
<h2 id="迭代器模式">迭代器模式</h2>
<p>迭代器模式,提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。</p>
<p>迭代器模式是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。</p>
<p><code>foreach</code> 其实是一个迭代器模式的语法糖,用来遍历一个集合中的数据,<code>foreach</code> 可以使用 <code>while</code> 来实现,比如下面这个示例:</p>
<pre><code class="language-csharp">var enumerable = Enumerable.Range(1, 10).ToArray();
foreach (var i in enumerable)
{
Console.WriteLine(i);
}
</code></pre>
<p>使用 <code>while</code> 重写之后类似下面这样的代码:</p>
<pre><code class="language-csharp">var enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
</code></pre>
<p>c# 中的集合基本都实现了迭代器模式,可以直接使用 <code>foreach</code> 来遍历,对于自定义的类型想要支持 <code>foreach</code> 可以实现 <code>IEnumerable</code> 或 <code>IEnumerable<T></code>,对于没有实现迭代器的代码,是不是可以用 <code>foreach</code> 呢</p>
<h2 id="enumerator">Enumerator</h2>
<p>我们再来看开篇提到的问题,怎么实现支持 <code>foreach</code> 呢</p>
<p><img src="https://img2020.cnblogs.com/blog/489462/202012/489462-20201228233850498-556193090.png" alt="vs tips" loading="lazy"></p>
<p>从上面 VS 的提示我们可以看得出来,如果一个类型想要支持 <code>foreach</code>,有三种方式可以实现:</p>
<ol>
<li>实现 <code>IEnumerable</code></li>
<li>实现 <code>IEnmuerable<T></code></li>
<li>添加 <code>GetEnumerator</code> 方法,方法返回值类型需要有 <code>Current</code> 属性和 <code>MoveNext</code> 方法,可以参考这个 <code>IEnumerator</code>,返回类型可以直接实现 <code>IEnumerator</code> 或 <code>IEnumerator<T></code></li>
</ol>
<p>那么如果是一个别人封装的类型,能否支持 <code>foreach</code> 呢,从 C# 9 之后就可以了,可以添加一个 <code>GetEnumerator</code> 的扩展方法,类似于下面</p>
<pre><code class="language-csharp">public static class ForEachExtensions
{
public static IEnumerator<char> GetEnumerator(this int num)
{
return num.ToString().GetEnumerator();
}
}
</code></pre>
<p>此时如果是使用 C# 9 就可以编译通过了,如果手动设置了 <code>LangVersion</code>,需要修改为 9,否则会得到类似下面这样的错误</p>
<p><img src="https://img2020.cnblogs.com/blog/489462/202012/489462-20201228233928345-932533576.png" alt="" loading="lazy"></p>
<p>添加使用扩展方法,并启用 C# 9 语法:</p>
<p><img src="https://img2020.cnblogs.com/blog/489462/202012/489462-20201228233957106-991315011.png" alt="" loading="lazy"></p>
<p><img src="https://img2020.cnblogs.com/blog/489462/202012/489462-20201228234013594-1497313298.png" alt="" loading="lazy"></p>
<h2 id="more">More</h2>
<p>有了这个功能之后,一切类型都是可以 <code>foreach</code> 的,没有实现迭代器模式的类型,只需要实现一个扩展方法就可以了</p>
<p>迎接 C# 9 ,万物皆可 <code>foreach</code> ~~</p>
<h2 id="reference">Reference</h2>
<ul>
<li>https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9</li>
<li>https://github.com/WeihanLi/SamplesInPractice/tree/master/CSharp9Sample</li>
<li>https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp9Sample/ForEachExtensions.cs</li>
</ul>
</div>
<div id="MySignature" role="contentinfo">
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。<br><br>
来源:https://www.cnblogs.com/weihanli/p/14204347.html
頁:
[1]