Span<T>.Enumerator 结构
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
为 Span<T> 的元素提供枚举器。
public: value class Span<T>::Enumerator
public ref struct Span<T>.Enumerator
type Span<'T>.Enumerator = struct
Public Structure Span(Of T).Enumerator
类型参数
- T
- 继承
注解
C# 语言的 C# foreach 和 For Each...Visual Basic 中的下一个 构造隐藏枚举器的复杂性。 建议使用或For Each...Next
建议直接操作枚举器,而不是直接foreach
操作枚举器。
最初,枚举器位于第 Span<T>一个元素之前。 在此位置上,未定义 Current。 必须调用MoveNext枚举器,才能在读取值Current之前将枚举器推进到第一项Span<T>。
Current 返回相同的值,直到 MoveNext 调用为止。 MoveNext 设置为 Current 下 Span<T>一项。
如果 MoveNext 传递末尾 Span<T>, MoveNext 则 false
返回。 当枚举器处于此状态时,后续调用 MoveNext 也会返回 false
且 Current 未定义。 不能再次设置为 Current 第一项 Span<T> ;必须改为创建新的枚举器实例。
枚举器无权访问 Span<T>该枚举器。 此外,还可以修改跨度的基础数据。 因此,通过范围枚举本质上不是线程安全的过程。 若要保证枚举期间的线程安全性,必须实现自己的同步。 例如,以下代码具有争用条件。 它不确保在执行方法之前 ClearContents
枚举跨度。 因此,在范围枚举期间清除基础数组:
using System;
using System.Threading.Tasks;
class Program
{
private static readonly byte[] _array = new byte[5];
static void Main()
{
new Random(42).NextBytes(_array);
Span<byte> span = _array;
Task.Run( () => ClearContents() );
EnumerateSpan(span);
}
public static void ClearContents()
{
Task.Delay(20).Wait();
lock (_array)
{
Array.Clear(_array, 0, _array.Length);
}
}
public static void EnumerateSpan(Span<byte> span)
{
foreach (byte element in span)
{
Console.WriteLine(element);
Task.Delay(10).Wait();
}
}
}
// The example displays output like the following:
// 62
// 23
// 186
// 0
// 0
module Program
open System
open System.Threading.Tasks
let array = Array.zeroCreate<byte> 5
let clearContents () =
Task.Delay(20).Wait()
lock array (fun () ->
Array.Clear(array, 0, array.Length) )
let enumerateSpan (span: Span<byte>) =
for element in span do
printfn $"{element}"
Task.Delay(10).Wait()
[<EntryPoint>]
let main _ =
Random(42).NextBytes array
printfn "%A" array
let span: Span<byte> = array
Task.Run clearContents |> ignore
enumerateSpan span
0
// The example displays output like the following:
// 62
// 23
// 186
// 0
// 0
如果在枚举范围之前同步对数组的访问,如以下示例中方法的修订版本 EnumerateSpan
一样,该方法 ClearContents
不会在枚举期间修改基础跨度数据。 请注意,该示例锁定跨度所基于的基础数组。
public static void EnumerateSpan(Span<byte> span)
{
lock (_array)
{
foreach (byte element in span)
{
Console.WriteLine(element);
Task.Delay(10).Wait();
}
}
}
// The example displays the following output:
// 62
// 23
// 186
// 150
// 174
let enumerateSpan (span: Span<byte>) =
// Spans cannot be accessed in closures including in the F# lock function.
// Monitor.Enter and Monitor.Exit are used here directly.
Monitor.Enter array
try
for element in span do
printfn $"{element}"
Task.Delay(10).Wait()
finally
Monitor.Exit array
// The example displays the following output:
// 62
// 23
// 186
// 150
// 174
与 .NET 中的其他一些枚举器结构不同, Span<T>.Enumerator如下:
不实现 IEnumerator 或 IEnumerator<T> 接口。 这是因为 Span<T>.Enumerator 是 一个 ref 结构。
不包括方法
Reset
,该方法可以将枚举器设置为其初始位置,然后再在跨度中的第一个元素之前。 IEnumerator.Reset() (该方法必须作为接口的一部分实现,但大多数实现者要么引发异常,要么不提供任何实现。)
属性
Current |
获取对枚举器当前位置的项目的引用。 |
方法
MoveNext() |
将枚举器推进到 Span<T> 的下一项。 |