Last active
April 19, 2024 12:24
-
-
Save theodorzoulias/46936d9c04fb45630a0d6782d6ce2546 to your computer and use it in GitHub Desktop.
JsonKeyedCollectionBase for JSON serialization/deserialization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Related: https://github.com/dotnet/runtime/issues/101003 -- [API Proposal]: New method HashSet<T>.Add that replaces an existing element if found | |
abstract class JsonKeyedCollectionBase<TKey, TItem> : ICollection<TItem>, IEqualityComparer<TItem> | |
{ | |
private readonly HashSet<TItem> _set; | |
protected abstract TKey GetKeyForItem(TItem item); | |
protected abstract TItem GetItemForKey(TKey key); | |
protected virtual IEqualityComparer<TKey> KeyComparer => EqualityComparer<TKey>.Default; | |
protected virtual IComparer<TItem> EnumerationComparer => null; | |
protected JsonKeyedCollectionBase() | |
{ | |
_set = new((IEqualityComparer<TItem>)this); | |
} | |
public bool TryGetItem(TKey key, out TItem item) => _set.TryGetValue(GetItemForKey(key), out item); | |
public void Add(TItem item) | |
{ | |
if (_set.Add(item)) return; | |
bool removed = _set.Remove(item); | |
bool added = _set.Add(item); | |
Debug.Assert(removed); | |
Debug.Assert(added); | |
} | |
public bool Remove(TKey key) => _set.Remove(GetItemForKey(key)); | |
public IEnumerator<TItem> GetEnumerator() | |
{ | |
IComparer<TItem> comparer = EnumerationComparer; | |
return comparer is null ? _set.GetEnumerator() : _set.Order(comparer).GetEnumerator(); | |
} | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
bool IEqualityComparer<TItem>.Equals(TItem x, TItem y) => KeyComparer.Equals(GetKeyForItem(x), GetKeyForItem(y)); | |
int IEqualityComparer<TItem>.GetHashCode(TItem x) => KeyComparer.GetHashCode(GetKeyForItem(x)); | |
private ICollection<TItem> Collection => _set; | |
int ICollection<TItem>.Count => Collection.Count; | |
bool ICollection<TItem>.IsReadOnly => Collection.IsReadOnly; | |
bool ICollection<TItem>.Contains(TItem item) => Collection.Contains(item); | |
bool ICollection<TItem>.Remove(TItem item) => Collection.Remove(item); | |
void ICollection<TItem>.Clear() => Collection.Clear(); | |
void ICollection<TItem>.CopyTo(TItem[] array, int arrayIndex) => Collection.CopyTo(array, arrayIndex); | |
} | |
/* | |
// Usage example | |
readonly record struct MediaRecord(string FileName, DateTime TimeStamp, double Volume, double SpeedRatio); | |
class JsonMediaCollection : JsonKeyedCollectionBase<string, MediaRecord> | |
{ | |
private static readonly Comparer<MediaRecord> s_EnumerationComparer | |
= Comparer<MediaRecord>.Create((x, y) => x.TimeStamp.CompareTo(y.TimeStamp)); | |
protected override MediaRecord GetItemForKey(string key) => default(MediaRecord) with { FileName = key }; | |
protected override string GetKeyForItem(MediaRecord item) => item.FileName; | |
protected override IEqualityComparer<string> KeyComparer => StringComparer.OrdinalIgnoreCase; | |
protected override IComparer<MediaRecord> EnumerationComparer => s_EnumerationComparer; | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment