Table of Contents

Struct np.NDRefIter<T>

Namespace
NumSharp
Assembly
NumSharp.dll

The foreach-able returned by nditer<T>(NDArray, bool, char).

Why a ref struct enumerator. C#'s foreach is pattern-based — it needs only GetEnumerator/MoveNext/Current, no interface — so an enumerator exposing ref T Current gives foreach (ref T x in …) with no allocation, no boxing and no interface dispatch. Being a ref struct also makes the compiler enforce what this API needs anyway: neither the enumerator nor the ref it hands out can escape to a field, a lambda or an async frame.

This type holds no unmanaged state; the ENUMERATOR does. Each GetEnumerator() builds a fresh NDIterRef, which foreach then disposes through the same pattern (no IDisposable required). That is why this value is safe to keep and re-enumerate, and why every pass starts from the beginning — deliberately UNLIKE the class-based np.NDIterator, which is its own iterator (NumPy's iter(x) is x) and therefore resumes. Returning this from GetEnumerator — the np.Broadcast pattern — would be a use-after-free here: the first foreach frees the state that the second would then walk.

Order is 'K', i.e. MEMORY order — not logical C-order. This matches np.nditer exactly (probed against NumPy 2.4.2: a reversed view a[:, ::-1] of arange(6).reshape(2,3) yields 0 1 2 3 4 5 under the default order in BOTH libraries, and 2 1 0 5 4 3 under order='C'). It is also what lets reversed / F-contiguous / transposed views coalesce to a single chunk. For logical order — the order ndenumerate(NDArray) uses — pass order: 'C'.

public readonly struct np.NDRefIter<T> where T : unmanaged

Type Parameters

T

The array's exact element type.

Inherited Members
Extension Methods

Methods

GetEnumerator()

Builds a fresh iterator; foreach disposes it for you.

public np.NDRefIter<T>.Enumerator GetEnumerator()

Returns

np.NDRefIter<T>.Enumerator