2017-01-05 3 views
0

Я пытаюсь зарегистрировать класс как определенный интерфейс и использовать явные классы в качестве параметров его конструктора. Проблема в том, что все они реализуют тот же интерфейс, который с моей текущей регистрацией заканчивается в Autofac «Обнаружена зависимость циклического компонента».Вложенная регистрация с Autofac

Вот что я получил:

public interface IWorker 
{ 
    void DoWork(); 
} 
public class FirstLineWorker : IWorker 
{ 
    public void DoWork() 
    { 
     //Do some work 
    } 
} 
public class SecondLineWorker : IWorker 
{ 
    public void DoWork() 
    { 
     //Do some morework 
    } 
} 
public class SequentialWorker : IWorker 
{ 
    private readonly IList<IWorker> _workers; 

    public SequentialWorker(params IWorker[] workers) 
    { 
     _workers = workers; 
    } 

    public void DoWork() 
    { 
     foreach (var worker in _workers) 
     { 
      worker.DoWork(); 
     } 
    } 
} 

Как я могу в Autofac программно зарегистрировать SequentialWorker в IWorker с явными параметрами FirstLineWorker и SecondLineWorker?

Первая попытка, которая закончилась в круговом reigstration был:

var builder = new ContainerBuilder(); 
builder 
    .RegisterType<FirstLineWorker>() 
    .Named<IWorker>(typeof(FirstLineWorker).Name) 
    .InstancePerDependency(); 
builder 
    .RegisterType<SecondLineWorker>() 
    .Named<IWorker>(typeof(SecondLineWorker).Name) 
    .InstancePerDependency(); 
builder.RegisterType<SequentialWorker>() 
    .As<IWorker>() 
    .WithParameter(ResolvedParameter.ForNamed<IWorker>(typeof(FirstLineWorker).Name)) 
    .WithParameter(ResolvedParameter.ForNamed<IWorker>(typeof(SecondLineWorker).Name)) 
    .InstancePerDependency(); 

Любые идеи?

ответ

1

Для вас доступно как минимум 2 подхода. Во-первых, создать новый пустой интерфейс, полученный из IWorker, как

public interface IWorkExecutor : IWorker { } 

Затем зарегистрируйте «нормальные» рабочие, как IWorker и «исполнитель», как IWorkExecutor

builder.RegisterType<Worker1>().As<IWorker>(); 
builder.RegisterType<Worker2>().As<IWorker>(); 
builder.RegisterType<SequentialWorker>().As<IWorkExecutor>(); 

Второй подход был бы очень похож к коду у вас уже есть:

containerBuilder.RegisterType<Worker1>().Named<IWorker>(nameof(Worker1)); 
containerBuilder.RegisterType<Worker2>().Named<IWorker>(nameof(Worker2)); 
containerBuilder.RegisterType<SequentialWorker>().As<IWorker>() 
    .WithParameter(new ResolvedParameter(
     (pi, cc) => pi.Name == "workers", 
     (pi, cc) => new [] { cc.ResolveNamed<IWorker>(nameof(Worker1)), cc.ResolveNamed<IWorker>(nameof(Worker2)) })); 

вы должны пройти один параметр массива для params IWorker[] workers я n SequentialWorker.

BTW InstancePerDependency() на самом деле не требуется, так как это область видимости по умолчанию при регистрации типов.

+0

ИМХО первый подход лучше - чище и более удобным для чтения. Кроме того, на самом деле роль Worker1 и Worker2 слабее, чем SequentialWorker, даже если они имеют один и тот же интерфейс – tdragon

1

Ответы частично на вопрос this о сложном шаблоне (который вы реализуете здесь).

Решение зарегистрировать все услуги с общим названием и решить названную коллекцию в регистрации для композита:

builder 
    .RegisterType<FirstLineWorker>() 
    .Named<IWorker>("worker") 
    .InstancePerDependency(); 
builder 
    .RegisterType<SecondLineWorker>() 
    .Named<IWorker>("worker") 
    .InstancePerDependency(); 

и либо

builder 
    .Register<IWorker>(c => new SequentialWorker(
      c.ResolveNamed<IEnumerable<IWorker>>("worker").ToArray())) 
    .As<IWorker>() 
    .InstancePerDependency(); 

или

builder.RegisterType<SequentialWorker>() 
    .As<IWorker>() 
    .WithParameter(new ResolvedParameter(
     (pi, cc) => pi.Name == "workers", 
     (pi, cc) => cc.ResolveNamed<IEnumerable<IWorker>>("worker").ToArray())); 

также стоит упомянуть, что params на самом деле не требуется IRED, вы можете использовать IEnumerable как это позволяет избежать необходимости выполнения ToArray() при разрешении "worker" «s

public SequentialWorker(IEnumerable<IWorker> workers) 
{ 
    _workers = workers; 
} 
Смежные вопросы