Building a C# cache with byte[] key, and eviction policy

.net, c#

Solution

`MemoryCache` is actually fairly complex under the hood (grab a copy of Reflector and take a look if you haven't already). There are several things it does which are non-trivial to replicate; chief among these is approximating memory size used by cached objects.

Performance-wise, you will be contending with much more significant impacts than the massaging of a key. Performance is acceptable, but key management is an insignificant part of the process.

You can see this difference by performing 100K+ add operations on a `Dictionary` versus `MemoryCache`.

Here's a little hex algorithm you can use on your byte keys which I have tweaked to be as fast as possible. The BCL also contains base 16 functionality (which I didn't know when I wrote this code and I've kept it around because it is simpler/faster).

As noted in the comments, converting the `byte[]` to hex is probably not even needed to meet the stated requirements unless the key will be used elsewhere.

public unsafe sealed class Hex
{
    private static readonly char[] _hexRange = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    /// <summary>
    /// Converts a byte array into a string of base-16 values.
    /// </summary>
    /// <param name="value">Value to convert.</param>
    /// <returns>Base-16 encoded string.</returns>
    public static string ToHexString( byte[] value )
    {
        char* buffer = stackalloc char[( value.Length * 2 ) + 1]; // +1 for null terminator
        char* start = buffer;

        for( int i = 0; i < value.Length; i++ )
        {
            *buffer++ = _hexRange[value[i] / 16];
            *buffer++ = _hexRange[value[i] % 16];
        }

        return new string( start );
    }
}

Problem

I'm wanting to build a cache with an eviction policy in C#. My key is a byte array (fixed at 32 bytes) and value is an instance of a specific class. I'm debating the best way to do this. I'm thinking that `MemoryCache` is the way to go, but it uses `string` for a key. I could turn this into a hex-string but that incurs some overhead. Why isn't the key an arbitrary object like in a dictionary? It's trivial to write a byte array comparer and there's a suitable `Dictionary` constructor to supply an `IEqualityComparer`, but this approach doesn't give me an eviction strategy for free. Are there any other options I'm overlooking?

Original source