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# のforeachとVisual BasicのFor Each...Next構造は、列挙子の複雑さを隠します。 列挙子を直接操作するのではなく、foreach
またはFor Each...Next
を使用することをお勧めします。
初期状態で、列挙子はSpan<T>内の最初の要素の前に配置されます。 この位置では、Current が未定義です。 Currentの値を読み取る前に、MoveNextを呼び出し、列挙子をSpan<T>の最初の項目に進める必要があります。
MoveNextが呼び出されるまで、Current は同じ値を返します。 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
Span<T>.Enumeratorは、.NETの他の列挙子構造体とは異なります。
IEnumeratorまたはIEnumerator<T>インターフェイスを実装しません。 これは、Span<T>.Enumeratorがref 構造体であるためです。
列挙子をスパン内の最初の要素より前の初期位置に設定する、
Reset
メソッドは含まれません。 (IEnumerator.Reset()メソッドは、インターフェイスの一部として実装する必要がありますが、ほとんどの実装が例外をスローするか、実装されていません。)
プロパティ
Current |
列挙子の現在位置にある項目への参照を取得します。 |
メソッド
MoveNext() |
列挙子を Span<T> の次の項目に進めます。 |