Thursday, August 15, 2013

Stable Hash Codes and Abstract Base Classes

I like to use abstract base classes for my value objects. One of my most used is for identities:

public abstract class Identity<TId>
    where TId : Identity<TId>
{
    private readonly string _prefix;
    public abstract string Value { get; protected set; }

    /* ... */

    protected Identity(string value, string prefix)
        : this(prefix)
    {
        Value = value;
    }

    // So we can deserialize and have access to the prefix
    protected Identity(string prefix)
    {
        _prefix = prefix; 
    }
}

Since the identities are value objects, we need to make sure that any two identities of the same type with the same values are considered equal.

public abstract class Identity<TId> : IEquatable<TId>
    where TId : Identity<TId>
{
    private readonly string _prefix;
    public abstract string Value { get; protected set; }

    public bool Equals(TId other)
    {
        if (ReferenceEquals(null, other)) return false;
        return ReferenceEquals(this, other) || Equals(Value, other.Value);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, other)) return false;
        return ReferenceEquals(this, obj) || Equals(obj as TId);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            var hash = 17;
            hash += hash * 23 + Value.GetHashCode();
            hash += hash * 23 + GetType().GetHashCode();
            return hash;
        }
    }

    public override string ToString() { return string.Format("{0}/{1}", _prefix, Value); }

    protected Identity(string value, string prefix)
        : this(prefix)
    {
        Value = value;
    }

    // So we can deserialize and have access to the prefix
    protected Identity(string prefix)
    {
        _prefix = prefix; 
    }
}

Almost...

This works for most situations but, recently, I found out that there's a little bit of a bug with the implementation of GetHashCode(). The overall algorithm is pretty sound for most cases, minus one little piece: GetType().GetHashCode(). The way I found out this doesn't work is by having to persist the hash between uses of an app. Bringing the app down and back up caused GetType().GetHashCode() to return a different value. Whoops!

(The reason for GetType().GetHashCode() was so that two identities of different types with the same .Value; would return different hashes.)

I switched it up, for now, to use GetType().Name. Fixed the issue for me.

public abstract class Identity<TId> : IEquatable<TId>
    where TId : Identity<TId>
{
    /* ... */
    public override int GetHashCode()
    {
        unchecked
        {
            var hash = 17;
            hash += hash * 23 + Value.GetHashCode();
            hash += hash * 23 + GetType().Name.GetHashCode();
            return hash;
        }
    }
    /* ... */
}

And, to wrap up the use of this class, here's a sample of how to use it (fully serializable, too):

[DataContract(Namespace = "my-namespace")]
public abstract class ProductId : Identity<ProductId>
{
    [DataMember(Order = 1)]
    public override string Value { get; protected set; }

    public ProductId(long id)
        : base(id.ToString(CultureInfo.InvariantCulture), "product") { }

    private ProductId()
        : base("product") { }
}

Thursday, August 8, 2013

Registering Open Generics to a Factory Method with StructureMap Using Expression Trees

I have been working with a system lately that requires a factory method to create a lot of open generics. To keep it simple, at the beginning, I registered each type of instance with something like the following:

var singletonFactory = new OpenGenericFactory();

StructureMap.ObjectFactory.Configure(cfg =>
{
    cfg.For<IOpenGeneric<int, int>>().Use(OpenGenericFactory.GetGeneric<int, int>());
    cfg.For<IOpenGeneric<int, long>>().Use(OpenGenericFactory.GetGeneric<int, long>());
    cfg.For<IOpenGeneric<long, long>>().Use(OpenGenericFactory.GetGeneric<long, long>());
    cfg.For<IOpenGeneric<long, int>>().Use(OpenGenericFactory.GetGeneric<long, int>());
});

The actual classes don't matter much, other than it is an open generic with two generic arguments and there would be a lot of registering. Not fun at all, especially because it is easy to forget to go register them and it's a really boring manual task. I fairly simple solution is to bind the open generic like so:

var singletonFactory = new OpenGenericFactory();
var getGenericMethod = singletonFactory.GetType().GetMethod("GetGeneric");

StructureMap.ObjectFactory.Configure(cfg =>
{
    cfg.For(typeof(IOpenGeneric<,>).Use(x =>
    {
        var requestedType = x.BuildStack.Current.RequestedType;
        var genericArgs = requestedType.GetGenericArguments();
        var genericMethod = getGenericMethod.MakeGenericMethod(genericArgs);
        return genericMethod.Invoke(singletonFactory, null);
    });
});

This turns out to be orders of magnitude slower than registering each type by hand. One could go ahead and cache the "genericMethod" in a dictionary, but it is still pretty slow. Instead, we can create a Func out of the method and cache that. This one time compile of an expression tree (cached, of course) makes everything much faster.

using System.Linq.Expressions; // This is where the Expression tools live

var singletonFactory = new OpenGenericFactory();
var factoryType = singletonFactory.GetType();
var getGenericMethod = factoryType.GetMethod("GetGeneric");
var cache = new ConcurrentDictionary<Type, Func<OpeGenericFactory, object>>();

StructureMap.ObjectFactory.Configure(cfg =>
{
    cfg.For(typeof(IOpenGeneric<,>).Use(x =>
    {
        var requestedType = x.BuildStack.Current.RequestedType;
        var func = cache.GetOrAdd(requestedType, type =>
        {
            var genericArgs = type.GetGenericArguments();
            var genericMethod = getGenericMethod.MakeGenericMethod(genericArgs);
            var input = Expression.Parameter(factoryType, "input");
            return Expression.Lambda<Func<OpenGenericFactory, object>>(Expression.Call(input, genericMethod), input).Compile();
        }
        return func(singletonFactory);
    });
});

So, after a one-time reflection payment, we can use the method as if we were calling it directly. Fun!