Span<T>.Enumerator 结构

定义

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
继承
Span<T>.Enumerator

注解

C# 语言的 C# foreachFor Each...Visual Basic 中的下一个 构造隐藏枚举器的复杂性。 建议使用或For Each...Next建议直接操作枚举器,而不是直接foreach操作枚举器。

最初,枚举器位于第 Span<T>一个元素之前。 在此位置上,未定义 Current。 必须调用MoveNext枚举器,才能在读取值Current之前将枚举器推进到第一项Span<T>

Current 返回相同的值,直到 MoveNext 调用为止。 MoveNext 设置为 CurrentSpan<T>一项。

如果 MoveNext 传递末尾 Span<T>MoveNextfalse返回。 当枚举器处于此状态时,后续调用 MoveNext 也会返回 falseCurrent 未定义。 不能再次设置为 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如下:

属性

Current

获取对枚举器当前位置的项目的引用。

方法

MoveNext()

将枚举器推进到 Span<T> 的下一项。

适用于