2017-10-04 104 views
0

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

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

不,这是不可能做到这一点。第一个代码是好的,不需要改进。

你另一个想法是使用通用类的静态字段,而不是并发词典:

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; 
} 

但需要注意的泛型类中静态变量不推荐使用。

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类的功能,你可以只更换objectAggregateRoot然后将强制转换为该方法的结束。

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; 
}