Skip to content

Instantly share code, notes, and snippets.

@egil
Last active March 22, 2024 11:37
Show Gist options
  • Save egil/924f37c10a68abbe8f52c4049d87fe73 to your computer and use it in GitHub Desktop.
Save egil/924f37c10a68abbe8f52c4049d87fe73 to your computer and use it in GitHub Desktop.
RecordList - a List<T> that supports deep equality and hashing that include items in the list. The equality is does not take order of items into consideration. Useful in combination with C# record types.
public sealed class RecordList<T> : List<T>, IEquatable<RecordList<T>>
where T : IEquatable<T>
{
private static readonly int EmptyRecordListHashCode = typeof(RecordList<T>).FullName!.GetHashCode(StringComparison.Ordinal);
public RecordList()
{
}
public RecordList(IEnumerable<T> collection)
: base(collection)
{
}
public RecordList(int capacity)
: base(capacity)
{
}
public bool Equals(RecordList<T>? other)
{
if (other is null || Count != other.Count)
{
return false;
}
return GetHashCode() == other.GetHashCode();
}
public override bool Equals(object? obj)
=> Equals(obj as RecordList<T>);
public static bool operator ==(RecordList<T> x, RecordList<T> y) => !(x is null || y is null) && x.Equals(y);
public static bool operator !=(RecordList<T> x, RecordList<T> y) => !(x == y);
public override int GetHashCode()
{
var hashCode = EmptyRecordListHashCode;
for (int i = 0; i < Count; i++)
{
hashCode += EqualityComparer<T>.Default.GetHashCode(this[i]) * -1521134295;
}
return hashCode;
}
public override string ToString() => $"[{string.Join(", ", this)}]";
}
public static class EnumerableExtensions
{
public static RecordList<TSource> ToRecordList<TSource>(this IEnumerable<TSource> source)
where TSource : IEquatable<TSource>
{
ArgumentNullException.ThrowIfNull(source);
return new RecordList<TSource>(source);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment