Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should a cache key be created from multiple keys?

Tags:

caching

I have a method whose output I'll be caching. It takes four parameters; string, string, int, and WindowsIdentity. I need to create a cache key based on those four parameters. Is it best to:

Concatenate them all together as strings and use that key?

var key = string.Concat(string1, string2, int1.ToString(), identity.ToString());

Or

Xor together their hash codes?

var key = string1.GetHashCode() ^ string2.GetHashCode() ^ int1.GetHashCode() ^ identity.GetHashCode();

Or something else? Does it matter? In my particular case, these keys will just be going into a Hashtable (C# v1).

like image 655
EliThompson Avatar asked Dec 23 '22 01:12

EliThompson


1 Answers

Create a new type which encapsulates the four values. For example:

public sealed class User
{
    private readonly string name;
    private readonly string login;
    private readonly int points;
    private readonly WindowsIdentity identity;

    public User(string name, string login, int points,
                WindowsIdentity identity)
    {
        this.name = name;
        this.login = login;
        this.points = points;
        this.identity = identity;
    }

    public string Name { get { return name; } }
    public string Login { get { return login; } }
    public int Points { get { return points; } }
    public WindowsIdentity Identity { get { return identity; } }

    public override bool Equals(object other)
    {
        User otherUser = other as User;
        if (otherUser == null)
        {
            return false;
        }
        return name == otherUser.name &&
               login == otherUser.login &&
               points == otherUser.points &&
               identity.Equals(otherUser.identity);
    }

    public override int GetHashCode()
    {
        int hash = 17;
        hash = hash * 31 + name.GetHashCode();
        hash = hash * 31 + login.GetHashCode();
        hash = hash * 31 + points.GetHashCode();
        hash = hash * 31 + identity.GetHashCode();
        return hash;
    }
}

Note that this assumes that WindowsIdentity overrides Equals and GetHashCode appropriately - or that you're happy with reference type equality.

This approach is a lot more robust than either of your suggestions - for example, in your first approach the two string pairs "xy", "z" and "x", "yz" would end up forming the same cache key (if the int and identity were the same) whereas they shouldn't. The second approach is even more likely to lead to accidental hash collisions.

like image 156
Jon Skeet Avatar answered Jan 15 '23 15:01

Jon Skeet