tags:

views:

35

answers:

4

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).

A: 

Use whatever you want that fits the semantics of a lookup key and the framework will deal with the details of hashing/re-hashing/buckets from there. (I've had people tell me I'm wrong about this in the past so maybe they will happen again here, we'll see)

Gabriel
+1  A: 

I'd be a little nervous about the latter because there is a small chance of your keys clashing. This could lead to you retrieving incorrect data for a record (with serious security / privacy implications depending on your application's usage).

The primary goal of your key is to be unique, so eliminate methods that do not ensure this is the case and choose the best from the remainder.

adamnfish
A: 

Yu can go with yure first step only... its cleaner way.. doesn't involve much effort...

Disclaimer: yu need tu be so sure that yu send the proper values when yu create the key...

Trust me, i have a similar implementation which is working fine...

raj!

Raj
+2  A: 

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.

Jon Skeet