繁体   English   中英

通用字典的类型约束

[英]Type constraint on generic dictionary

我正在使用反射来查找给定类型的构造函数。 然后,我想缓存键入其类型的构造函数,以便下次需要构造函数时可以即时使用它。 下面的代码这样做了,但是它要求我按原样存储构造函数,然后返回一个对象,然后将其强制转换为所需的类型。 我希望有一种方法可以使其更安全。

private static readonly ConcurrentDictionary<Type, Func<Guid, object>> AggregateConstructors = new ConcurrentDictionary<Type, Func<Guid, object>>();

public TAggregate GetAggregate<TAggregate>(Guid aggregateId) where TAggregate : AggregateRoot
{
    var constructor = AggregateConstructors.GetOrAdd(typeof(TAggregate), GetConstructorFunc<TAggregate>());
    // Requires a cast.  
    var aggregate = (TAggregate)constructor(aggregateId);

    var history = eventStore.GetDomainEvents(aggregateId);
    aggregate.LoadFromHistory(history);

    return aggregate;
}

private Func<Guid, TAggregate> GetConstructorFunc<TAggregate>()
{
    var parameter = Expression.Parameter(typeof(Guid), "aggregateId");
    var constructor = typeof(TAggregate).GetConstructor(new[] { typeof(Guid) });
    var lambda = Expression.Lambda<Func<Guid, TAggregate>>(Expression.New(constructor, parameter), parameter);
    return lambda.Compile();
}

我想遵循以下思路:

private static readonly ConcurrentDictionary<Type, Func<Guid, SameTypeAsKey>> AggregateConstructors = new ConcurrentDictionary<Type, Func<Guid, SameTypeAsKey>>();

public TAggregate GetAggregate<TAggregate>(Guid aggregateId) where TAggregate : AggregateRoot
{
    var constructor = AggregateConstructors.GetOrAdd(typeof(TAggregate), GetConstructorFunc<TAggregate>());
    var aggregate = constructor(aggregateId);

    var history = eventStore.GetDomainEvents(aggregateId);
    aggregate.LoadFromHistory(history);

    return aggregate;
}

private Func<Guid, TAggregate> GetConstructorFunc<TAggregate>()
{
    var parameter = Expression.Parameter(typeof(Guid), "aggregateId");
    var constructor = typeof(TAggregate).GetConstructor(new[] { typeof(Guid) });
    var lambda = Expression.Lambda<Func<Guid, TAggregate>>(Expression.New(constructor, parameter), parameter);
    return lambda.Compile();
}

不,这是不可能的。 第一个代码还可以,不需要改进。

对您来说,另一个想法是使用带有静态字段的通用类而不是并发字典:

static class AggregateConstructors<TAggregate>
{
    public static Func<Guid, TAggregate> Value { get; private set; }
    public static TAggregate Create(Guid aggregateId) => Value(aggregateId);

    static AggregateConstructors()
    {
        var parameter = Expression.Parameter(typeof(Guid), "aggregateId");
        var constructor = typeof(TAggregate).GetConstructor(new[] { typeof(Guid) });
        var lambda = Expression.Lambda<Func<Guid, TAggregate>>(Expression.New(constructor, parameter), parameter);
        Value = lambda.Compile();
    }
}

public TAggregate GetAggregate<TAggregate>(Guid aggregateId) where TAggregate : AggregateRoot
{
    var aggregate = AggregateConstructors<TAggregate>.Create(aggregateId);

    var history = eventStore.GetDomainEvents(aggregateId);
    aggregate.LoadFromHistory(history);

    return aggregate;
}

但是请注意,不建议使用泛型类中的静态变量。

一种选择是,您只需要添加另一层即可覆盖为您执行转换的字典。 这很可能是一种扩展方法

public static class ExtensionMethods
{
    public static Func<Guid, TAggregate> GetOrAdd<TAggregate>(this ConcurrentDictionary<Type, Func<Guid, object>> @this, Func<Guid, TAggregate> factory)
    {
        var constructor = @this.GetOrAdd(typeof(TAggregate), (key) => factory);
        return (guid) => (TAggregate)constructor(guid);
    }
}

这可以让你做

public TAggregate GetAggregate<TAggregate>(Guid aggregateId) where TAggregate : AggregateRoot
{
    var constructor = AggregateConstructors.GetOrAdd<TAggregate>(GetConstructorFunc<TAggregate>());
    var aggregate = constructor(aggregateId);

    var history = eventStore.GetDomainEvents(aggregateId);
    aggregate.LoadFromHistory(history);

    return aggregate;
}

另一个选择是,如果LoadFromHistoryAggregateRoot基类上的函数,则可以只用AggregateRoot替换object ,然后将强制类型转换移到方法的末尾。

public TAggregate GetAggregate<TAggregate>(Guid aggregateId) where TAggregate : AggregateRoot
{
    var constructor = AggregateConstructors.GetOrAdd(typeof(TAggregate), GetConstructorFunc<TAggregate>());
    // Requires a cast.  
    var aggregate = constructor(aggregateId);

    var history = eventStore.GetDomainEvents(aggregateId);
    aggregate.LoadFromHistory(history);

    return (TAggregate)aggregate;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM