Skip to content

Instantly share code, notes, and snippets.

@RichardD2
Last active September 19, 2025 10:30
Show Gist options
  • Select an option

  • Save RichardD2/eaee2550edfe848ba2daf47ab6c7e8dc to your computer and use it in GitHub Desktop.

Select an option

Save RichardD2/eaee2550edfe848ba2daf47ab6c7e8dc to your computer and use it in GitHub Desktop.
EquatableArray
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace NBS.Collections.Generic;
[CollectionBuilder(typeof(EquatableArray), nameof(EquatableArray.Create))]
public readonly struct EquatableArray<T>(T[] values, IEqualityComparer<T>? comparer = default) : IReadOnlyList<T>, IEquatable<EquatableArray<T>>
{
private readonly T[] _values = values;
private readonly IEqualityComparer<T> _comparer = comparer ?? EqualityComparer<T>.Default;
public int Length => _values?.Length ?? 0;
int IReadOnlyCollection<T>.Count => Length;
public T this[int index] => _values is null ? throw new IndexOutOfRangeException() : _values[index];
public Enumerator GetEnumerator() => new(_values);
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
// Required to support collection expressions:
[Obsolete("This method is not supported.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void Add(T item) => throw new NotSupportedException();
public override int GetHashCode()
{
if (_values is null or []) return 0;
HashCode code = new();
for (int index = 0; index < _values.Length; index++)
{
code.Add(_values[index], _comparer);
}
return code.ToHashCode();
}
public override bool Equals(object? obj) => obj is EquatableArray<T> other && Equals(other);
public bool Equals(EquatableArray<T> other)
{
if (Length != other.Length) return false;
if (_values is null or []) return true;
for (int index = 0; index < _values.Length; index++)
{
if (!_comparer.Equals(_values[index], other._values[index]))
{
return false;
}
}
return true;
}
public static bool operator ==(EquatableArray<T> left, EquatableArray<T> right) => left.Equals(right);
public static bool operator !=(EquatableArray<T> left, EquatableArray<T> right) => !left.Equals(right);
public struct Enumerator(T[]? array) : IEnumerator<T>
{
private readonly T[] _array = array ?? [];
private int _current = -1;
public T Current
{
get
{
if (_current < 0 || _current >= _array.Length) throw new InvalidOperationException();
return _array[_current];
}
}
object? IEnumerator.Current => Current;
public bool MoveNext()
{
if (_current < _array.Length)
{
_current++;
return _current < _array.Length;
}
return false;
}
public void Reset()
{
_current = -1;
}
public void Dispose()
{
}
}
}
public static class EquatableArray
{
public static EquatableArray<T> Create<T>(params ReadOnlySpan<T> values) => new(values.ToArray());
public static EquatableArray<T> Create<T>(T[] values) => new(values);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment