Skip to content

Instantly share code, notes, and snippets.

@udlose
Last active April 22, 2026 20:24
Show Gist options
  • Select an option

  • Save udlose/78281c1e1a995ac4e0bf7400c19416bf to your computer and use it in GitHub Desktop.

Select an option

Save udlose/78281c1e1a995ac4e0bf7400c19416bf to your computer and use it in GitHub Desktop.
for vs. foreach iteration over List<Guid>
// LinqPad BenchmarkDotNet script
// Compares for-loop (indexer) vs foreach (struct enumerator) over List<T>
// at sizes relevant to EntryDoor slab definition lists.
//
// Required NuGet: BenchmarkDotNet
//
// NOTE: Set the target framework and runtime in your LinqPad/project settings.
void Main()
{
BenchmarkRunner.Run<ForVsForeachBenchmarks>(DefaultConfig.Instance
.WithOption(ConfigOptions.DisableOptimizationsValidator, true)
.AddColumn(RankColumn.Arabic)
.AddColumn(StatisticColumn.OperationsPerSecond)
.WithSummaryStyle(SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend)));
}
/// <summary>
/// Compares for-loop with indexer access vs foreach (struct enumerator)
/// over a concretely-typed List of reference-type elements.
///
/// The element type simulates EntryDoorSlabDefinition: a reference type
/// with two Guid fields, matching the access pattern in EnsureIndexBuilt
/// where each iteration reads properties from the element.
/// </summary>
[MemoryDiagnoser]
[HideColumns("Error", "StdDev", "Median")]
public class ForVsForeachBenchmarks
{
// Sizes matching real entry door datasets:
// 68 = Masonite Entry Doors slab count
// 1393 = ThermaTru slab count
// 7744 = Masonite Interior Doors slab count
// 10000 = round number requested by Dave
[Params(68, 1393, 7744, 10_000)]
public int Size { get; set; }
private List<SlabElement> _list;
[GlobalSetup]
public void Setup()
{
_list = new List<SlabElement>(Size);
for (int i = 0; i < Size; i++)
{
_list.Add(new SlabElement(Guid.NewGuid(), Guid.NewGuid()));
}
}
[Benchmark(Baseline = true)]
public Guid Foreach_StructEnumerator()
{
Guid last = Guid.Empty;
foreach (SlabElement item in _list)
{
last = item.QuestionID;
}
return last;
}
[Benchmark]
public Guid For_IndexerAccess()
{
Guid last = Guid.Empty;
for (int i = 0; i < _list.Count; i++)
{
last = _list[i].QuestionID;
}
return last;
}
}
/// <summary>
/// Simulates EntryDoorSlabDefinition or GenericQuestionToAnswer:
/// a reference type with two Guid fields accessed during iteration.
/// </summary>
public class SlabElement
{
public Guid QuestionID { get; set; }
public Guid AnswerID { get; set; }
public SlabElement(Guid questionId, Guid answerId)
{
QuestionID = questionId;
AnswerID = answerId;
}
}
* Summary *
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8246/25H2/2025Update/HudsonValley2)
12th Gen Intel Core i7-12800H 2.40GHz, 1 CPU, 20 logical and 14 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9325.0), X64 RyuJIT VectorSize=256
DefaultJob : .NET Framework 4.8.1 (4.8.9325.0), X64 RyuJIT VectorSize=256
| Method | Size | Mean | Op/s | Ratio | RatioSD | Rank | Allocated | Alloc Ratio |
|------------------------- |------ |-------------:|-------------:|-------------:|--------:|-----:|----------:|------------:|
| Foreach_StructEnumerator | 68 | 163.44 ns | 6,118,292.5 | baseline | | 2 | - | NA |
| For_IndexerAccess | 68 | 56.31 ns | 17,757,451.2 | 2.90x faster | 0.06x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 1393 | 3,133.66 ns | 319,115.2 | baseline | | 2 | - | NA |
| For_IndexerAccess | 1393 | 1,227.10 ns | 814,926.6 | 2.55x faster | 0.05x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 7744 | 17,631.53 ns | 56,716.6 | baseline | | 2 | - | NA |
| For_IndexerAccess | 7744 | 6,577.42 ns | 152,035.4 | 2.68x faster | 0.07x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 10000 | 22,692.85 ns | 44,066.7 | baseline | | 2 | - | NA |
| For_IndexerAccess | 10000 | 8,326.14 ns | 120,103.6 | 2.73x faster | 0.06x | 1 | - | NA |
// * Summary *
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8246/25H2/2025Update/HudsonValley2)
12th Gen Intel Core i7-12800H 2.40GHz, 1 CPU, 20 logical and 14 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9325.0), X86 LegacyJIT
DefaultJob : .NET Framework 4.8.1 (4.8.9325.0), X86 LegacyJIT
| Method | Size | Mean | Op/s | Ratio | RatioSD | Rank | Allocated | Alloc Ratio |
|-
------------------------ |------ |-------------:|-------------:|-------------:|--------:|-----:|----------:|------------:|
| Foreach_StructEnumerator | 68 | 171.42 ns | 5,833,701.8 | baseline | | 2 | - | NA |
| For_IndexerAccess | 68 | 80.93 ns | 12,355,835.0 | 2.12x faster | 0.07x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 1393 | 3,065.97 ns | 326,161.0 | baseline | | 2 | - | NA |
| For_IndexerAccess | 1393 | 1,622.88 ns | 616,187.1 | 1.89x faster | 0.03x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 7744 | 17,128.98 ns | 58,380.6 | baseline | | 2 | - | NA |
| For_IndexerAccess | 7744 | 9,455.26 ns | 105,761.3 | 1.82x faster | 0.09x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 10000 | 21,224.53 ns | 47,115.3 | baseline | | 2 | - | NA |
| For_IndexerAccess | 10000 | 12,265.93 ns | 81,526.6 | 1.73x faster | 0.09x | 1 | - | NA |
* Summary *
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8246/25H2/2025Update/HudsonValley2)
12th Gen Intel Core i7-12800H 2.40GHz, 1 CPU, 20 logical and 14 physical cores
.NET SDK 10.0.202
[Host] : .NET 10.0.6 (10.0.6, 10.0.626.17701), X64 RyuJIT x86-64-v3
| Method | Size | Mean | Op/s | Ratio | RatioSD | Rank | Allocated | Alloc Ratio |
|------------------------- |------ |------------:|-------------:|-------------:|--------:|-----:|----------:|------------:|
| Foreach_StructEnumerator | 68 | 32.48 ns | 30,789,043.5 | baseline | | 1 | - | NA |
| For_IndexerAccess | 68 | 34.70 ns | 28,822,482.8 | 1.07x slower | 0.02x | 2 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 1393 | 839.80 ns | 1,190,765.6 | baseline | | 2 | - | NA |
| For_IndexerAccess | 1393 | 752.16 ns | 1,329,505.2 | 1.12x faster | 0.02x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 7744 | 4,746.08 ns | 210,700.2 | baseline | | 2 | - | NA |
| For_IndexerAccess | 7744 | 4,205.01 ns | 237,811.7 | 1.13x faster | 0.02x | 1 | - | NA |
| | | | | | | | | |
| Foreach_StructEnumerator | 10000 | 9,259.58 ns | 107,996.3 | baseline | | 1 | - | NA |
| For_IndexerAccess | 10000 | 9,679.24 ns | 103,313.9 | 1.09x slower | 0.26x | 1 | - | NA |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment