SoFunction
Updated on 2025-03-07

How to implement a dictionary based on value equality comparison

Intro

Today I encountered a requirement in the project. I probably want to compare whether two JSON strings are equal. The JSON string is actually one.Dictionary<string, string>But the order may be different, andPrevious article record usage scenarioThe first requirement in this article is similar. We have introduced that using record can be more convenient to solve, but our project is.netcoreapp3.1 , cannot be usedrecord, how to compare more conveniently? Can we implement a similarrecordWhat are the types of , based on the values? So this article is explored

StringValueDictioanry

Implemented a dictionary based on values. The implementation code is as follows. The implementation is relatively simple and involves some simple knowledge points. I forgot how to write it if I don’t use it very much. I learned it again by writing the following code.

Let’s take a look at the test code first, the test code is as follows:

[Fact]
public void EqualsTest()
{
 var abc = new { Id = 1, Name = "Tom" };
 var dic1 = (abc);
 var dic2 = (new Dictionary<string, object>()
 {
 {"Name", "Tom" },
 {"Id", 1},
 });

 (dic1 == dic2);
 (dic1, dic2);
}

[Fact]
public void DistinctTest()
{
 var abc = new { Id = 1, Name = "Tom" };
 var dic1 = (abc);
 var dic2 = (new Dictionary<string, object>()
 {
 {"Id", 1},
 {"Name", "Tom" },
 });
 var set = new HashSet<StringValueDictionary>();
 (dic1);
 (dic2);

 (set);
}

[Fact]
public void CloneTest()
{
 var dic1 = (new Dictionary<string, object>()
 {
 {"Id", 1},
 {"Name", "Tom" }
 });
 var dic2 = ();
 (ReferenceEquals(dic1, dic2));
 (dic1 == dic2);
}

[Fact]
public void ImplicitConvertTest()
{
 var abc = new { Id = 1, Name = "Tom" };
 var stringValueDictionary = (abc);
 Dictionary<string, string> dictionary = stringValueDictionary;
 (, );

 var dic2 = (dictionary);

 (dic2, stringValueDictionary);
 (dic2 == stringValueDictionary);
}

From the above code, we can probably see some implementations, and rewrite the default oneEqualsandGetHashCode, and overload the "==" operator and implement aStringValueDictionaryarrive Dictionary Let's look at the following implementation code:

public sealed class StringValueDictionary : IEquatable<StringValueDictionary>
{
 private readonly Dictionary<string, string?> _dictionary = new();

 private StringValueDictionary(IDictionary<string, string?> dictionary)
 {
 foreach (var pair in dictionary)
 {
  _dictionary[] = ;
 }
 }

 private StringValueDictionary(StringValueDictionary dictionary)
 {
 foreach (var key in )
 {
  _dictionary[key] = dictionary[key];
 }
 }

 public static StringValueDictionary FromObject(object obj)
 {
 if (obj is null) throw new ArgumentNullException(nameof(obj));
 if (obj is IDictionary<string, string?> dictionary)
 {
  return new StringValueDictionary(dictionary);
 }
 if (obj is IDictionary<string, object?> dictionary2)
 {
  return new StringValueDictionary((p => , p => ?.ToString()));
 }
 if (obj is StringValueDictionary dictionary3)
 {
  return new StringValueDictionary(dictionary3);
 }
 return new StringValueDictionary(().GetProperties()
  .ToDictionary(p => , p => (obj)?.ToString()));
 }

 public static StringValueDictionary FromJson(string json)
 {
 (json, nameof(json));
 var dic = <Dictionary<string, object?>>()
  .ToDictionary(x => , x => ?.ToString());
 return new StringValueDictionary(dic);
 }

 public StringValueDictionary Clone() => new(this);

 public int Count => _dictionary.Count;

 public bool ContainsKey(string key) => _dictionary.ContainsKey(key) ? _dictionary.ContainsKey(key) : throw new ArgumentOutOfRangeException(nameof(key));

 public string? this[string key] => _dictionary[key];

 public Dictionary<string, string>.KeyCollection Keys => _dictionary.Keys!;

 public bool Equals(StringValueDictionary? other)
 {
 if (other is null) return false;
 if ( != Count) return false;
 foreach (var key in _dictionary.Keys)
 {
  if (!(key))
  {
  return false;
  }
  if (_dictionary[key] != other[key])
  {
  return false;
  }
 }
 return true;
 }

 public override bool Equals(object obj)
 {
 return Equals(obj as StringValueDictionary);
 }

 public override int GetHashCode()
 {
 var stringBuilder = new StringBuilder();
 foreach (var pair in _dictionary)
 {
  ($"{}={}_");
 }
 return ().GetHashCode();
 }

 public static bool operator ==(StringValueDictionary? current, StringValueDictionary? other)
 {
 return current?.Equals(other) == true;
 }

 public static bool operator !=(StringValueDictionary? current, StringValueDictionary? other)
 {
 return current?.Equals(other) != true;
 }

 public static implicit operator Dictionary<string, string?>(StringValueDictionary dictionary)
 {
 return dictionary._dictionary;
 }
}

More

The above code is implemented a bit rough and may have some problems. For reference only

The above code basically achieves the goal of comparing the equality of the desired values ​​and Clone (copy, cloning)

When achieving equality comparison,EqualsandGetHashCodeThe method must also be rewritten, if notGetHashCode, the compiler will also give a warning if it is not rewriteGetHashCodeIn factHashSet orDictionaryThere may be duplication inkey

When overloading operators, a static method is needed. "==" and "!=" are a pair of operation operators. If you want to implement both, you cannot only implement one of them.

implicit is also a special operator. Clever use of implicit conversion can greatly simplify the writing of the code.Used inimplicitTo achieveRedisValueandstringImplicit conversions of other common types

References

/WeihanLi//blob/dev/src//Models/
/WeihanLi//blob/dev/test//ModelsTest/

The above is the detailed content of how C# implements a dictionary based on value equality comparison. For more information about c# implementing a dictionary for value equality comparison, please pay attention to my other related articles!