Question Details

No question body available.

Tags

best-practices c#

Answers (2)

Accepted Answer Available
Accepted Answer
July 23, 2026 Score: 4 Rep: 1,528,753 Quality: Expert Completeness: 60%

Note: I'd reserve doing this for once you've actually validated that you need it. The .NET garbage collector is really good at collecting short-lived objects. But if you do need this, it's doable.

You can write your own struct that supports iteration using foreach the fact that C# foreach is based on patterns of methods etc, not just on the interfaces we normally use. You don't have to implement IEnumerable - just supporting an appropriate GetEnumerator() method is enough, and that can return your own pair enumerator type (which can be a struct).

Iterating over this with a foreach loop will call GetEnumerator(), and use MoveNext() and Current on the returned enumerator - without any attempt to cast anything to IEnumerable, IEnumerator, IEnumerable or IEnumerator.

The downside is it requires a mutable struct, which is smelly, but it does avoid heap allocations.

Code which works for the sample below, and is fairly simple - it can easily be misused though, e.g. using new Pair() or new Pair.PairEnumerator...

public readonly struct Pair
{
    public T First { get; }
    public T Second { get; }

public Pair(T first, T second) { First = first; Second = second; }

public PairEnumerator GetEnumerator() => new PairEnumerator(this);

// Warning: mutable struct, only for use when iterating. public struct PairEnumerator { private readonly Pair parent; private int index;

internal PairEnumerator(Pair parent) => this.parent = parent;

public bool MoveNext() { if (index parent.First, 2 => parent.Second, _ => throw new InvalidOperationException() }; } }

Sample usage:

string x = "first";
string y = "second";

foreach (var z in new Pair(x, y)) { Console.WriteLine(z); }

You could easily create a non-generic Pair static class with a Create(T first, T second) => new Pair(first, second) to take advantage of type inference.

You could also implement IEnumerable so that you could pass it into LINQ etc... although at that point it would be boxed.

July 23, 2026 Score: 3 Rep: 80,999 Quality: Medium Completeness: 80%

You can cast a collection expression to (Span) and the compiler will use an internal struct with the InlineArray attribute. This is entirely non-heap-allocating.

Person p1 = new(); Person p2 = new(); // ... foreach (Person p in (Span)[p1, p2]) { p.DoSomething(); p.DoMoreStuff(); }

Sharplab.io


To do this in older versions of C#, you can just create it yourself. You still need at least C# version 8, and .NET version 8 (and as far as I know it's not supported in Unity).

[InlineArray(2)] private struct ArrayOf2 { private T element0;

public ArrayOf2(T item0, T item1) { AsSpan()[0] = item0; AsSpan()[1] = item1; }

public Span AsSpan() => MemoryMarshal.CreateSpan(ref
element0, 2); }

Alternately use a struct with fields, and SequentialLayout then get a span off that.

[StructLayout(LayoutKind.Sequential)] private struct ArrayOf2 { private T element0; private T element0;

public ArrayOf2(T item0, T item1) { element0 = item0; element1 = item1; }

public Span AsSpan() => MemoryMarshal.CreateSpan(ref _element0, 2); }

Person p1 = new(); Person p2 = new(); // ... foreach (Person p in new ArrayOf2(p1, p2).AsSpan()) { p.DoSomething(); p.DoMoreStuff(); }