using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Collections.Immutable; public class EquatableDictionary : IEnumerable>, IString, IEquatable> { public readonly ImmutableDictionary dictionary; public EquatableDictionary() { this.dictionary = ImmutableDictionary.Empty; this.hashCode = "EquatableDictionary".GetHashCode(); } public EquatableDictionary(ImmutableDictionary dictionary) { this.dictionary = dictionary; this.hashCode = dictionary.Aggregate( "EquatableDictionary".GetHashCode(), (h, kvp) => h ^ kvp.Key.GetHashCode() ^ kvp.Value.GetHashCode()); } private EquatableDictionary(EquatableDictionary dictionary, TKey key, TValue value) { this.dictionary = dictionary.dictionary.Add(key, value); this.hashCode = dictionary.hashCode ^ key.GetHashCode() ^ value.GetHashCode(); } public TValue this[TKey key] { get => dictionary[key]; } public EquatableDictionary Add(TKey key, TValue value) => new EquatableDictionary(this, key, value); // These would need to update the hashCode, disabled for now. /*public EquatableDictionary SetItem(TKey key, TValue value) => new EquatableDictionary(dictionary.SetItem(key, value)); public EquatableDictionary Remove(TKey key) => new EquatableDictionary(dictionary.Remove(key));*/ public IEnumerator> GetEnumerator() => dictionary.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => dictionary.GetEnumerator(); /*public EquatableDictionaryLens< TKey, TValue, EquatableDictionary> lens { get => this.ChainLens(x => x); }*/ public override string ToString() => "EquatableDictionary {\n" + this.Select(kvp => (ks: kvp.Key.ToString(), vs: kvp.Value.ToString())) .OrderBy(p => p.ks) .Select(p => $"{{ {p.ks}, {p.vs} }}") .JoinWith(",\n") + "\n}"; public string Str() => ToString(); private bool SameKVP(EquatableDictionary other) { foreach (var kvp in this) { // Let's hope that this uses EqualityComparer.Default and EqualityComparer.Default. if (!other.Contains(kvp)) { return false; } } foreach (var kvp in this) { if (!this.Contains(kvp)) { return false; } } return false; } public override bool Equals(object other) => Equality.Untyped>( this, other, x => x as EquatableDictionary, x => x.hashCode, (x, y) => x.SameKVP(y)); public bool Equals(EquatableDictionary other) => Equality.Equatable>(this, other); private readonly int hashCode; public override int GetHashCode() => hashCode; } public static class EquatableDictionaryExtensionMethods { public static EquatableDictionary ToEquatableDictionary(this IEnumerable e, Func key, Func value) => new EquatableDictionary(e.ToImmutableDictionary(key, value)); public static EquatableDictionary ToEquatableDictionary(this ImmutableDictionary d) => new EquatableDictionary(d); }