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
TThe 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()