2017-10-04 14 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

1つのオプションは、キャストを行うディクショナリを経由する別のレイヤーを追加するだけです。これは、簡単にこれはあなたがLoadFromHistoryは、あなただけのAggregateRootobjectを置き換えることができますベースAggregateRootクラス上の機能であれば別のオプションは、その後にキャストを移動さ

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

を行うことができます拡張メソッド

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(typeof(TAggregate), GetConstructorFunc<TAggregate>()); 
    // Requires a cast. 
    var aggregate = constructor(aggregateId); 

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

    return (TAggregate)aggregate; 
} 
関連する問題