我使用反射来查找给定类型的构造函数。然后我想缓存键入其类型的构造函数,以便我可以在下次需要构造函数时动态使用它。下面的代码是这样做的,但是它要求我将构造函数存储为返回一个对象,然后将其转换为所需的类型。我希望有一种方法可以使它更安全。
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();
}
答案 0 :(得分:0)
不,不可能这样做。第一个代码没问题,不需要改进。
另一个想法是使用泛型类而不是并发字典:
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;
}
但请注意,不建议使用泛型类中的静态变量。
答案 1 :(得分:0)
一个选项是你只需要添加另一个层来覆盖为你做演员的字典。这很容易成为一种扩展方法
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;
}
另一种选择是,如果LoadFromHistory
是基础AggregateRoot
类的函数,则可以用object
替换AggregateRoot
,然后将强制转换移动到方法的末尾。
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;
}