7

I'm trying to implement a cache for JObjects.

I was surprised to see that they didn't override the GetHashCode method and therefore, I can't use it as a unique key.

Since my json's are pretty large, I don't want to use JObject.ToString().GetHashCode as a solution.

I did see that they have an internal method called GetDeepHashCode but the implementation is based on other protected properties and therefore, I cannot "copy" the code and create an extension method from it.

I also don't want to use reflection and invoke the internal GetDeepHashCode method.

I'm looking for a way to create a unique cache key for a JObject and I don't want the method to be extra expensive when it comes to performance.

Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
  • 1
    Are you sure that you want to use GetHashCode as a unique key? According to the definition different objects don't need to have different hash codes – Harald Coppoolse Sep 15 '16 at 09:20
  • Are you expecting the hash codes to be the same after a round-trip to and from a string representation? Because a `JValue` can contain a `double`, and doubles [do not round-trip without precision loss](http://stackoverflow.com/questions/24299692/why-is-a-round-trip-conversion-via-a-string-not-safe-for-a-double). – dbc Sep 15 '16 at 09:22
  • @HaraldCoppoolse - I understand that and I understand that when you have collisions the Equals method is invoked. That's the reason that you need to override Equals when you override GetHashCode. Since they didn't override GetHashCode, I'm looking for a fast way to do that. – Amir Popovich Sep 15 '16 at 09:22
  • @dbc - I'm trying to avoid the round trip to and from string. I don't care if I lose some cache hit's on specific occasions. – Amir Popovich Sep 15 '16 at 09:24
  • 1
    What I mean is, if you round-trip a `JValue` containing a double from and to JSON, its hash code may change. Anyway, use [`JTokenEqualityComparer`](http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenEqualityComparer.htm), it does what you need. – dbc Sep 15 '16 at 09:26
  • @dbc - I understood you comment regarding the double and the class was exactly what I was looking for. The GetHashCode method excepts a JToken as a parameter. Please post this as an answer. Thank you. – Amir Popovich Sep 15 '16 at 09:30

1 Answers1

9

You can use JTokenEqualityComparer.GetHashCode(JToken token) for this purpose. It provides access to the GetDeepHashCode() method you saw.

var obj = JToken.Parse(jsonString);
var comparer = new JTokenEqualityComparer();
var hashCode = comparer.GetHashCode(obj);

Note that JTokenEqualityComparer.Equals(JToken x, JToken y) calls JToken.DeepEquals() (source) so this comparer is suited for use as an IEqualityComparer<JToken> when constructing hash tables or dictionaries of LINQ-to-JSON objects and uniqueness of values is desired.

dbc
  • 104,963
  • 20
  • 228
  • 340