using BenchmarkDotNet.Attributes; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.VSDiagnostics; namespace AyCode.Benchmark; [CPUUsageDiagnoser] public class RefForeachBenchmark { // Simulates BinaryPropertyAccessor (large struct ~80 bytes) public struct PropertyAccessor { public int PropertyIndex; public TypeCode PropertyTypeCode; public int AccessorType; public long Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8; [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly int GetValue() => PropertyIndex + (int)PropertyTypeCode + AccessorType; } private PropertyAccessor[] _properties = null !; private List _propertiesList = null !; [GlobalSetup] public void Setup() { _properties = new PropertyAccessor[20]; // Typical property count _propertiesList = new List(20); for (int i = 0; i < 20; i++) { var prop = new PropertyAccessor { PropertyIndex = i, PropertyTypeCode = TypeCode.Int32, AccessorType = i % 5, Field1 = i, Field2 = i, Field3 = i, Field4 = i, Field5 = i, Field6 = i, Field7 = i, Field8 = i }; _properties[i] = prop; _propertiesList.Add(prop); } } // ============ ARRAY ITERATION ============ [Benchmark(Baseline = true)] public int Array_ForEach_ByValue() { int total = 0; for (int iter = 0; iter < 1000; iter++) { foreach (var prop in _properties) { total += prop.GetValue(); } } return total; } [Benchmark] public int Array_ForEach_RefReadonly() { int total = 0; for (int iter = 0; iter < 1000; iter++) { foreach (ref readonly var prop in _properties.AsSpan()) { total += prop.GetValue(); } } return total; } [Benchmark] public int Array_ForLoop_Index() { int total = 0; var props = _properties; for (int iter = 0; iter < 1000; iter++) { for (int i = 0; i < props.Length; i++) { total += props[i].GetValue(); } } return total; } [Benchmark] public int Array_ForLoop_Span() { int total = 0; for (int iter = 0; iter < 1000; iter++) { var span = _properties.AsSpan(); for (int i = 0; i < span.Length; i++) { total += span[i].GetValue(); } } return total; } // ============ LIST ITERATION ============ [Benchmark] public int List_ForEach_ByValue() { int total = 0; for (int iter = 0; iter < 1000; iter++) { foreach (var prop in _propertiesList) { total += prop.GetValue(); } } return total; } [Benchmark] public int List_CollectionsMarshal_RefReadonly() { int total = 0; for (int iter = 0; iter < 1000; iter++) { foreach (ref readonly var prop in CollectionsMarshal.AsSpan(_propertiesList)) { total += prop.GetValue(); } } return total; } [Benchmark] public int List_ForLoop_Index() { int total = 0; var props = _propertiesList; for (int iter = 0; iter < 1000; iter++) { for (int i = 0; i < props.Count; i++) { total += props[i].GetValue(); } } return total; } }