如何注册通用对象工厂?

Sam*_*Sam 5 .net generics autofixture open-generics

我有以下两个类:

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,
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

构造函数internal和第二个类存在的原因是我想强制执行更高度可维护的KeyedEntity.Create(x, y)语法而不是new KeyedEntity<T>{ Key = x, Entity = y }. (请注意,类型是用前一种语法推断出来的。)

我想告诉 AutoFixture 如何创建KeyedEntity. 但是,该Register方法似乎只允许注册单个类型而不是开放的泛型类型。

如何注册KeyedEntity.Create<TEntity>为 的创建函数KeyedEntity<TEntity>

Mar*_*ann 4

为了支持您的开放通用类型,您可以编写自定义样本生成器

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 });
    }
}
Run Code Online (Sandbox Code Playgroud)

(为了清楚起见,省略了防御性编码。)

以下单元测试通过:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

为了更好的可维护性,您应该封装KeyedEntityBuilder在 Customization 中