How can I register a generic object factory?

.net, autofixture, generics, open-generics

Solution

To support your open generic type, you can write a custom Specimen Builder:

public class KeyedEntityBuilder : ISpecimenBuilder
{
    private readonly static MethodInfo createMethod =
        typeof(KeyedEntity).GetMethod("Create");

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as Type;
        if (t == null ||
            !t.IsGenericType ||
            t.GetGenericTypeDefinition() != typeof(KeyedEntity<>))
            return new NoSpecimen(request);

        var entityType = t.GetGenericArguments().Single();

        var key = context.Resolve(typeof(Identifier));
        var entity = context.Resolve(entityType);

        return createMethod
            .MakeGenericMethod(entityType)
            .Invoke(null, new[] { key, entity });
    }
}

(Defensive coding omitted for clarity.)

The following unit test passes:

public class Tests
{
    [Fact]
    public void CreateKeyedEntity()
    {
        var fixture = new Fixture();
        fixture.ResidueCollectors.Add(new KeyedEntityBuilder());

        var actual = fixture.Create<KeyedEntity<Foo>>();

        Assert.NotNull(actual.Key);
        Assert.NotNull(actual.Entity);
    }
}

For better maintainability, you should encapsulate `KeyedEntityBuilder` in a Customization.

Problem

I have the following two classes: ``` public class KeyedEntity<TEntity> { internal KeyedEntity() { } public Identifier Key { get; set; } public TEntity Entity { get; set; } } public static class KeyedEntity { public static KeyedEntity<TEntity> Create<TEntity>(Identifier key, TEntity entity) { return new KeyedEntity<TEntity> { Key = key, Entity = entity, }; } } ``` The reason the constructor is `internal` and the second class exists is I want to enforce the more highly-maintainable `KeyedEntity.Create(x, y)` syntax rather than `new KeyedEntity<T>{ Key = x, Entity = y }`. (Note that the type is inferred with the former syntax.) I want to tell AutoFixture how to create an instance of `KeyedEntity`. However, the `Register` method only seems to allow registration of a single type rather than an open generic type. How can I register `KeyedEntity.Create<TEntity>` as the creation function for `KeyedEntity<TEntity>`?

Original source

Related problems