Есть еще один способ добиться этого без заводской зависимости от IUnityContainer
, что само по себе не плохо.Это просто другой способ думать о проблеме.
Процесс выглядит следующим образом:
- Зарегистрируйте все различные экземпляры
ICalculationRuleProcess
. - Получить всезарегистрируйте
ICalculationRuleProcess
и создайте лямбда-сотворение для каждого. - Зарегистрируйте
ICalculationRuleProcessFactory
со списком ICalculationRuleProcess
лямбда-сотворений. - В
ICalculationRuleProcessFactory.Create
верните нужный процесс.*
Теперь сложная часть этого заключается в том, чтобы сохранить идентификаторы, под которыми были сделаны регистрации.Однажды решение состоит в том, чтобы просто сохранить идентификатор на интерфейсе ICalculationProcess
, но он может не иметь семантической привязки.Вот где это решение выглядит ужасно (это скорее случай отсутствия функциональности в Unity).Но, с методом расширения и небольшим дополнительным типом, он хорошо выглядит при запуске.
Итак, мы делаем здесь метод расширения, который возвращает все регистрации с их именами.
public class Registration<T> where T : class {
public string Name { get; set; }
public Func<T> CreateLambda { get; set; }
public override bool Equals(object obj) {
var other = obj as Registration<T>;
if(other == null) {
return false;
}
return this.Name == other.Name && this.CreateLambda == other.CreateLambda;
}
public override int GetHashCode() {
int hash = 17;
hash = hash * 23 + (Name != null ? Name.GetHashCode() : string.Empty.GetHashCode());
hash = hash * 23 + (CreateLambda != null ? CreateLambda.GetHashCode() : 0);
return hash;
}
}
public static class UnityExtensions {
public static IEnumerable<Registration<T>> ResolveWithName<T>(this UnityContainer container) where T : class {
return container.Registrations
.Where(r => r.RegisteredType == typeof(T))
.Select(r => new Registration<T> { Name = r.Name, CreateLambda = ()=>container.Resolve<T>(r.Name) });
}
}
public class CalculationRuleProcessFactory : ICalculationRuleProcessFactory
{
private readonly IBatchStatusWriter _batchStatusWriter;
private readonly IEnumerable<Registration<ICalculationRuleProcess>> _Registrations;
public CalculationRuleProcessFactory(
IEnumerable<Registration<ICalculationRuleProcess>> registrations,
IBatchStatusWriter batchStatusWriter )
{
_batchStatusWriter = batchStatusWriter;
_Registrations= registrations;
}
public ICalculationRuleProcess Create( DistributionRule distributionRule )
{
_batchStatusWriter.WriteBatchStatusMessage(
string.Format( "Applying {0} Rule", distributionRule.Descr ) );
//will crash if registration is not present
return _Registrations
.FirstOrDefault(r=>r.Name == distributionRule.Id.ToString())
.CreateLambda();
}
}
//Registrations
var registrations = container.ResolveWithName<ICalculationRuleProcess>(container);
container.RegisterInstance<IEnumerable<Registration<ICalculationRuleProcess>>>(registrations);
После того, как я написал это, я понял, что это более креативное лямбда-дуче, чем архитектурно красивое решение.Но в любом случае, не стесняйтесь извлекать идеи из этого.