Condividi tramite


Span<T>.Enumerator Struct

Definizione

Fornisce un enumeratore per gli elementi di un 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

Parametri di tipo

T
Ereditarietà
Span<T>.Enumerator

Commenti

Foreach C# del linguaggio C# e For Each... Il costrutto successivo in Visual Basic nasconde la complessità degli enumeratori. Anziché modificare direttamente l'enumeratore, usando foreach o For Each...Next è consigliabile.

Inizialmente, l'enumeratore viene posizionato prima del primo elemento in Span<T>. In questa posizione, la proprietà Current è indefinita. È necessario chiamare MoveNext per avanzare l'enumeratore al primo elemento nell'oggetto Span<T> prima di leggere il valore di Current.

Current restituisce lo stesso valore finché non MoveNext viene chiamato. MoveNext imposta Current sull'elemento successivo in Span<T>.

Se MoveNext passa la fine di Span<T>, MoveNext restituisce false. Quando l'enumeratore si trova in questo stato, le chiamate successive per MoveNext restituire false e Current non sono definito. Non è possibile impostare Current nuovamente il primo elemento. È necessario creare invece una nuova istanza dell'enumeratore Span<T> .

L'enumeratore non ha accesso esclusivo all'oggetto Span<T>. Inoltre, i dati sottostanti su cui è basato l'intervallo possono anche essere modificati. Di conseguenza, l'enumerazione tramite un intervallo non è intrinsecamente una procedura thread-safe. Per garantire la sicurezza dei thread durante l'enumerazione, è necessario implementare la sincronizzazione personalizzata. Ad esempio, il codice seguente ha una condizione di gara. Non garantisce che l'intervallo venga enumerato prima dell'esecuzione del ClearContents metodo. Di conseguenza, la matrice sottostante viene cancellata durante l'enumerazione dell'intervallo:

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

Se si sincronizza l'accesso alla matrice prima di enumerare l'intervallo, poiché la versione modificata del EnumerateSpan metodo viene eseguita nell'esempio seguente, il ClearContents metodo non modifica i dati dell'intervallo sottostante durante l'enumerazione. Si noti che l'esempio blocca la matrice sottostante in cui si basa l'intervallo.

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

A differenza di altre strutture dell'enumeratore in .NET, l'oggetto Span<T>.Enumerator:

  • Non implementa l'interfaccia IEnumerator o IEnumerator<T> . Questo perché è Span<T>.Enumerator uno struct di riferimento.

  • Non include un Reset metodo, che può impostare l'enumeratore sulla posizione iniziale prima del primo elemento nell'intervallo. Il IEnumerator.Reset() metodo deve essere implementato come parte dell'interfaccia, ma la maggior parte degli implementori genera un'eccezione o non fornisce alcuna implementazione.

Proprietà

Current

Restituisce un riferimento all'elemento in corrispondenza della posizione corrente dell'enumeratore.

Metodi

MoveNext()

Sposta l'enumeratore all'elemento successivo dell'oggetto Span<T>.

Si applica a