韩筱 發表於 2020-11-25 09:19:00

关于C# Span的一些实践

<div id="output_wrapper_id" class="output_wrapper" style="font-size: 16px; color: rgba(62, 62, 62, 1); line-height: 1.6; word-spacing: 0; letter-spacing: 0; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif">
<blockquote style="line-height: inherit; display: block; padding: 15px 15px 15px 1rem; font-size: 0.9em; margin: 1em 0; color: rgba(129, 145, 152, 1); border-left: 6px solid rgba(220, 230, 240, 1); background-color: rgba(242, 247, 251, 1); overflow: auto; word-wrap: normal; word-break: normal">
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 0">Span这个东西出来很久了,居然因为5.0又火起来了。</p>
</blockquote>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"> </p>
<h1 id="h" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.6em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">相关知识</span></h1>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">在大多数情况下,C#开发时,我们只使用托管内存。而实际上,C#为我们提供了三种类型的内存:</p>
<ul style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0 0 0 32px; list-style-type: disc">
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0">堆栈内存 - 最快速的内存,能够做到极快的分配和释放。堆栈内存使用时,需要用<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">stackalloc</code>进行分配。堆栈的一个特点是空间非常小(通常小于1 MB),适合CPU缓存。试图分配更多堆栈会报出<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">StackOverflowException</code>错误并终止进程;另一个特点是生命周期非常短 - 方法结束时,堆栈会与方法的内存一起释放。<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">stackalloc</code>通常用于必须不分配任何托管内存的短操作。一个例子是在corefx中记录快速记录ETW事件:要求尽可能快,并且需要很少的内存。</li>
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0">非托管内存 - 通过<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">Marshal.AllocHGlobal</code>或<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">xMarshal.AllocCoTaskMem</code>方法分配在非托管堆上的内存。这个内存对GC不可见,并且必须通过<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">Marshal.FreeHGlobal</code>或<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">Marshal.FreeCoTaskMem</code>的显式调用来释放。使用非托管内存,最主要的目的是不给GC增加额外的压力,所以最经常的使用方式是在分配大量没有指针的值类型时使用。在<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">Kestrel</code>的代码中,很多地方用到了非托管内存。</li>
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0">托管内存 - 大多数代码中最常用的内存,需要用<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">new</code>操作符来分配。之所以称为托管(managed),因为它是被GC(垃圾管理器)管理的,由GC决定何时释放内存,而不需要开发人员考虑。GC又将托管对象根据大小(85000字节)分为大对象和小对象。两个对象的分配方式、速度和位置都有不同,小对象相对快点,大对象相对慢点。另外,两种对象的GC回收成本也不一样。</li>
</ul>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"><em style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; font-style: italic">&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: small; color: inherit; line-height: inherit; margin: 0; padding: 0">为防止非授权转发,这儿给出本文的原文链接:https://www.cnblogs.com/tiger-wang/p/14029853.html</span></em></p>
<h1 id="h-1" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.6em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">问题的产生</span></h1>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">问个问题:写了这么多年的C#,我们有用过指针吗?有没有想过为什么?</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">我们用个例子来回答这个问题:一个字符串,正常它是一个托管对象。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">如果我们想解析整个字符串,我们会这么写:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Parse</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">string</span>&nbsp;managedMemory)</span></span>;<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">那么,如果我们想只解析一部分字符串,该怎么写?</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Parse</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">string</span>&nbsp;managedMemory,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;startIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length)</span></span>;<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">现在,我们转到非托管内存上:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important">unsafe&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Parse</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>*&nbsp;pointerToUnmanagedMemory,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length)</span></span>;<br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important">unsafe&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Parse</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>*&nbsp;pointerToUnmanagedMemory,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;startIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length)</span></span>;<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">再延伸一下,我们写几个用于复制内存的功能:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;Copy&lt;T&gt;(T[]&nbsp;source,&nbsp;T[]&nbsp;destination);&nbsp;<br><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;Copy&lt;T&gt;(T[]&nbsp;source,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;sourceStartIndex,&nbsp;T[]&nbsp;destination,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;destinationStartIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;elementsCount);<br>unsafe&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;Copy&lt;T&gt;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;source,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;destination,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;elementsCount);<br>unsafe&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;Copy&lt;T&gt;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;source,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;sourceStartIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;destination,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;destinationStartIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;elementsCount);<br>unsafe&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;Copy&lt;T&gt;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;source,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;sourceLength,&nbsp;T[]&nbsp;destination);<br>unsafe&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;Copy&lt;T&gt;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;source,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;sourceStartIndex,&nbsp;T[]&nbsp;destination,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;destinationStartIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;elementsCount);<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">是不是很复杂?而且看上去并不安全?</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">所以,问题并不在于我们能不能用,而在于这种支持会让代码变得复杂,而且并不安全 - 直到Span出现。</p>
<h1 id="hspan" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.6em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Span</span></h1>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">在定义中,Span就是一个简单的值类型。它真正的价值,在于允许我们与任何类型的连续内存一起工作。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">这些所谓的连续内存,包括:</p>
<ul style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0 0 0 32px; list-style-type: disc">
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">非托管内存缓冲区</span></li>
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">数组和子串</span></li>
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">字符串和子字符串</span></li>
</ul>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">在使用中,Span确保了内存和数据安全,而且几乎没有开销。</p>
<h2 id="hspan-1" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.4em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">使用Span</span></h2>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">要使用Span,需要设置开发语言为C# 7.2以上,并引用<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">System.Memory</code>到项目。</p>
<pre><code class="xml language-xml hljs" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-tag" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">&lt;<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">PropertyGroup</span>&gt;</span><br>&nbsp;&nbsp;<span class="hljs-tag" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">&lt;<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">LangVersion</span>&gt;</span>7.2<span class="hljs-tag" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">&lt;/<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">LangVersion</span>&gt;</span><br><span class="hljs-tag" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">&lt;/<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(215, 55, 55, 1); word-wrap: inherit !important; word-break: inherit !important">PropertyGroup</span>&gt;</span><br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">使用低版本编译器,会报错:<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">Error CS8107 Feature 'ref structs' is not available in C# 7.0. Please use language version 7.2 or greater.</code>。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"> </p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">Span使用时,最简单的,可以把它想象成一个数组,它会做所有的指针运算,同时,内部又可以指向任何类型的内存。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">例如,我们可以为非托管内存创建Span:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important">Span&lt;byte&gt;&nbsp;stackMemory&nbsp;=&nbsp;stackalloc&nbsp;byte[<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">256</span>];<br><br>IntPtr&nbsp;unmanagedHandle&nbsp;=&nbsp;Marshal.AllocHGlobal(<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">256</span>);<br>Span&lt;byte&gt;&nbsp;unmanaged&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">new</span>&nbsp;Span&lt;byte&gt;(unmanagedHandle.ToPointer(),&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">256</span>);&nbsp;<br>Marshal.FreeHGlobal(unmanagedHandle);<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">从<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">T[]</code>到Span的隐式转换:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>[]&nbsp;<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">array</span>&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">new</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>[]&nbsp;{&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'i'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'m'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'p'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'l'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'i'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'c'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'i'</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">'t'</span>&nbsp;};<br>Span&lt;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>&gt;&nbsp;fromArray&nbsp;=&nbsp;<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">array</span>;<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"> </p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">此外,还有ReadOnlySpan,可以用来处理字符串或其他不可变类型:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important">ReadOnlySpan&lt;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>&gt;&nbsp;fromString&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(96, 172, 57, 1); word-wrap: inherit !important; word-break: inherit !important">"Hello&nbsp;world"</span>.AsSpan();<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"> </p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">Span创建完成后,就跟普通的数组一样,有一个<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">Length</code>属性和一个允许读写的<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">index</code>,因此使用时就和一般的数组一样使用就好。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">看看Span常用的一些定义、属性和方法:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important">Span(T[]&nbsp;<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">array</span>);<br>Span(T[]&nbsp;<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">array</span>,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;startIndex);<br>Span(T[]&nbsp;<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">array</span>,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;startIndex,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length);<br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important">unsafe&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Span</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>*&nbsp;memory,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length)</span></span>;<br><br><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;Length&nbsp;{&nbsp;get;&nbsp;}<br>ref&nbsp;T&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">this</span>[<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;index]&nbsp;{&nbsp;get;&nbsp;<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">set</span>;&nbsp;}<br><br>Span&lt;T&gt;&nbsp;Slice(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;start);<br>Span&lt;T&gt;&nbsp;Slice(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;start,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length);<br><br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Clear</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">()</span></span>;<br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Fill</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(T&nbsp;value)</span></span>;<br><br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">CopyTo</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(Span&lt;T&gt;&nbsp;destination)</span></span>;<br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">bool</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">TryCopyTo</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(Span&lt;T&gt;&nbsp;destination)</span></span>;<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"> </p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">我们用Span来实现一下文章开头的复制内存的功能:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Parse</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(ReadOnlySpan&lt;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">char</span>&gt;&nbsp;anyMemory)</span></span>;<br><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;Copy&lt;T&gt;(ReadOnlySpan&lt;T&gt;&nbsp;source,&nbsp;Span&lt;T&gt;&nbsp;destination);<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">看看,是不是非常简单?</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">而且,使用Span时,运行性能极佳。关于Span的性能,网上有很多评测,关注的兄弟可以自己去看。</p>
<h2 id="hspan-2" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.4em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Span的限制</span></h2>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">Span支持所有类型的内存,所以,它也会有相当严格的限制。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">在上面的例子中,使用的是堆栈内存。所有指向堆栈的指针都不能存储在托管堆上。因为方法结束时,堆栈会被释放,指针会变成无效值,如果再使用,就是内存溢出。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">因此:Span实例也不能驻留在托管堆上,而只能驻留在堆栈上。这又引出一些限制。</p>
<ol style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0 0 0 32px; list-style-type: decimal">
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Span不能是非堆栈类型的字段</span></li>
</ol>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">如果在类中设置Span字段,它将被存储在堆中。这是不允许的:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-class" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">class</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Impossible</span><br>{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;Span&lt;byte&gt;&nbsp;field;<br>}<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">不过,从C# 7.2开始,在其他仅限堆栈的类型中有Span字段是可以的:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important">ref&nbsp;<span class="hljs-class" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">struct</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">TwoSpans</span>&lt;T&gt;<br>{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;Span&lt;T&gt;&nbsp;first;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;Span&lt;T&gt;&nbsp;second;<br>}&nbsp;<br></code></pre>
<ol style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0 0 0 32px; list-style-type: decimal" start="2">
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Span不能有接口实现</span></li>
</ol>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">接口实现意味着数据会被装箱。而装箱意味着存储在堆中。同时,为了防止装箱,Span必须不实现任何现有的接口,例如最容易想到的<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">IEnumerable</code>。也许某一天,C#会允许定义由结构体实现的结口?</p>
<ol style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0 0 0 32px; list-style-type: decimal" start="3">
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Span不能是异步方法的参数</span></li>
</ol>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">异步在C#里绝对是个好东西。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">不过对于Span,是另一件事。异步方法会创建一个<code style="font-size: inherit; line-height: inherit; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; color: rgba(233, 105, 0, 1); background-color: rgba(248, 248, 248, 1)">AsyncMethodBuilder</code>构建器,构建器会创建一个异步状态机。异步状态机会将方法的参数放到堆上。所以,Span不能用作异步方法的参数。</p>
<ol style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0 0 0 32px; list-style-type: decimal" start="4">
<li style="font-size: inherit; color: inherit; line-height: inherit; margin: 0 0 0.5em; padding: 0"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Span不能是泛型的代入参数</span></li>
</ol>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">看下面的代码:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important">Span&lt;byte&gt;&nbsp;Allocate()&nbsp;=&gt;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">new</span>&nbsp;Span&lt;byte&gt;(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">new</span>&nbsp;byte[<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">256</span>]);<br><br><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;CallAndPrint&lt;T&gt;(Func&lt;T&gt;&nbsp;valueProvider)&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;object&nbsp;value&nbsp;=&nbsp;valueProvider.Invoke();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(value.ToString());<br>}<br><br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Demo</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">()</span><br></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;Func&lt;Span&lt;byte&gt;&gt;&nbsp;spanProvider&nbsp;=&nbsp;Allocate;<br>&nbsp;&nbsp;&nbsp;&nbsp;CallAndPrint&lt;Span&lt;byte&gt;&gt;(spanProvider);<br>}<br></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">同样也是装箱的原因。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0"> </p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">上面是Span的内容。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">下面简单说一下另一个经常跟Span一起提的内容:Memory</p>
<h1 id="hmemory" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.6em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">Memory</span></h1>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">Memory是一个新的数据类型,它只能指向托管内存,所以不具有仅限堆栈的限制。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">Memory可以从托管数组、字符串或IOwnedMemory中创建,传递给异步方法或存储在类的字段中。当需要Span时,就调用它的Span属性。它会根据需要创建Span。然后在当前范围内使用它。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">看一下Memory的主要定义、属性和方法:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;readonly&nbsp;<span class="hljs-class" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">struct</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Memory</span>&lt;T&gt;<br>{</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">private</span>&nbsp;readonly&nbsp;object&nbsp;_object;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">private</span>&nbsp;readonly&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;_index;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">private</span>&nbsp;readonly&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;_length;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;Span&lt;T&gt;&nbsp;Span&nbsp;{&nbsp;get;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;Memory&lt;T&gt;&nbsp;Slice(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;start)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;Memory&lt;T&gt;&nbsp;Slice(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;start,&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">int</span>&nbsp;length)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">public</span>&nbsp;MemoryHandle&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">Pin</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">()</span><br>}<br></span></code></pre>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">使用也很简单:</p>
<pre><code class="c# language-c# hljs cpp" style="margin: 0 2px; line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0; letter-spacing: 0; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0; overflow-x: auto; background-color: rgba(254, 251, 236, 1); color: rgba(110, 107, 94, 1); padding: 0.5em; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow: auto !important">byte[]&nbsp;buffer&nbsp;=&nbsp;ArrayPool&lt;byte&gt;.Shared.Rent(<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">16000</span>&nbsp;*&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">8</span>);<br><br><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">while</span>&nbsp;((bytesRead&nbsp;=&nbsp;await&nbsp;fileStream.ReadAsync(buffer,&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">0</span>,&nbsp;buffer.Length))&nbsp;&gt;&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">0</span>)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ParseBlock(<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">new</span>&nbsp;ReadOnlyMemory&lt;byte&gt;(buffer,&nbsp;start:&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">0</span>,&nbsp;length:&nbsp;bytesRead));&nbsp;<br>}<br><br><span class="hljs-function" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0; word-wrap: inherit !important; word-break: inherit !important"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(184, 84, 212, 1); word-wrap: inherit !important; word-break: inherit !important">void</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(102, 132, 225, 1); word-wrap: inherit !important; word-break: inherit !important">ParseBlock</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0; padding: 0; color: rgba(182, 86, 17, 1); word-wrap: inherit !important; word-break: inherit !important">(ReadOnlyMemory&lt;byte&gt;&nbsp;memory)</span><br></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ReadOnlySpan&lt;byte&gt;&nbsp;slice&nbsp;=&nbsp;memory.Span;<br>}<br></code></pre>
<h1 id="h-2" style="color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0; font-weight: bold; font-size: 1.6em"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0; padding: 0">总结</span></h1>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">Span存在很长时间了,只是5.0做了一些优化。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">用好了,对代码是很好的补充和优化,用不好,就会有给自己刨很多个坑。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">所以,耗子尾汁。</p>
<p style="font-size: inherit; color: inherit; line-height: inherit; padding: 0; margin: 1.5em 0">&nbsp;</p>
<hr>
<p>&nbsp;</p>
<table border="0">
<tbody>
<tr>
<td><img src="https://img2020.cnblogs.com/blog/907112/202005/907112-20200527230728396-985375280.jpg"></td>
<td>
<p>微信公众号:老王Plus</p>
<p>扫描二维码,关注个人公众号,可以第一时间得到最新的个人文章和内容推送</p>
<p>本文版权归作者所有,转载请保留此声明和原文链接</p>
</td>
</tr>
</tbody>
</table>
</div><br><br>
来源:https://www.cnblogs.com/tiger-wang/p/14029853.html
頁: [1]
查看完整版本: 关于C# Span的一些实践