[英]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;
}
另一个选择是,如果LoadFromHistory
是AggregateRoot
基类上的函数,则可以只用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.