Span<T>.Enumerator Struct
Definition
Important
Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
Provides an enumerator for the elements of a 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
Type Parameters
- T
- Inheritance
Remarks
The C# foreach of the C# language and the For Each...Next construct in Visual Basic hides the complexity of enumerators. Instead of directly manipulating the enumerator, using foreach
or For Each...Next
is recommended.
Initially, the enumerator is positioned before the first element in the Span<T>. At this position, Current is undefined. You must call MoveNext to advance the enumerator to the first item in the Span<T> before reading the value of Current.
Current returns the same value until MoveNext is called. MoveNext sets Current to the next item in the Span<T>.
If MoveNext passes the end of the Span<T>, MoveNext returns false
. When the enumerator is at this state, subsequent calls to MoveNext also return false
and Current is undefined. You cannot set Current to the first item in the Span<T> again; you must create a new enumerator instance instead.
The enumerator does not have exclusive access to the Span<T>. In addition, the underlying data on which the span is based can also be modified. Therefore, enumerating through a span is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you must implement your own synchronization. For example, the following code has a race condition. It does not ensure that the span will be enumerated before the ClearContents
method executes. As a result, the underlying array is cleared during enumeration of the span:
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
If you synchronize access to the array before enumerating the span, as the revised version of the EnumerateSpan
method does in the following example, the ClearContents
method doesn't modify underlying span data during enumeration. Note that the example locks the underlying array on which the span is based.
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
Unlike some other enumerator structures in .NET, the Span<T>.Enumerator:
Does not implement the IEnumerator or IEnumerator<T> interface. This is because Span<T>.Enumerator is a ref struct.
Does not include a
Reset
method, which can set the enumerator to its initial position before the first element in the span. (The IEnumerator.Reset() method must be implemented as part of the interface, but most implementors either throw an exception or provide no implementation.)
Properties
Current |
Gets a reference to the item at the current position of the enumerator. |
Methods
MoveNext() |
Advances the enumerator to the next item of the Span<T>. |