Question
What's the best way to implement a function that given an object is able to return a hash key?
The requirements would be:
HashCodeFn(((bool?)false, "example")) != HashCodeFn(((bool?)null, "example"))
- Is relatively cheap to calculate
- Works with any type without any specific requirement (e.g.
[Serializable]
attribute)
What I've tried
I've tried with .GetHashCode
but:
- It's unreliable for things like
null
vs0
vsfalse
- Needs to be implemented for every type
I've tried with:
private static int GetHashKey<T>(T input)
{
using var memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, input);
memoryStream.Position = 0;
using var reader = new StreamReader(memoryStream);
return reader.ReadToEnd().GetHashCode();
}
but:
- It requires that all types in the object tree implement
[Serializable]
(some types I have no control over and don't implement those)
I'm thinking of serialising the object to JSON in the most compact form and then get the GetHashCode
of that string, but I'm not sure how well it works with something like NodaTime.Instant
. Is that the fastest way to accomplish this?
Specific use case
This is used as a data loader key (see github.com/graphql/dataloader for an example) if that is of any help to understand the use case.
Specifically a data loader key is used to handle batching. When you have many requests with input (a, b, c)
and you want to "pivot" on, for example, a
(which means that (1, b, c), (2, b, c), (3, b, c)
should call a batch function fn([1, 2, 3], (b, c))
then you need to be able to define a key that is the same for the same values of (b, c)
to use as the data loader key.
From the input perspective, specifying or not a bool on something like b
, for example, is considered to be 2 different things and should be batched on two different functions.
If I were to use (b, c).GetHashCode()
then I it would consider ((bool?)false, "ok")
and ((bool?)null, "ok")
to be the same thing, therefore batching them to the same batch function yielding unexpected results.