2015-06-20 2 views
3

Я использую autofac 3.5.x и я имею установку, подобную этой:Вводят зависимость с «конструктора сферы» - autofac

public class ServiceA : IServiceA { } 
public class ServiceB : IServiceB { public ServiceB(IServiceA sa) { } } 
public class ServiceC : IServiceC { public ServiceC(IServiceA sa) { } } 
public class ServiceD : IServiceD { public ServiceD(IServiceA sa, IServiceB sb, IServiceC sc) {} } 

В моем контейнере у меня есть следующие регистрации:

builder.RegisterType<ServiceA>.As<IServiceA>(); 
builder.RegisterType<ServiceB>.As<IServiceB>(); 
builder.RegisterType<ServiceC>.As<IServiceC>(); 
builder.RegisterType<ServiceD>.As<IServiceD>(); 

Вот что я хочу: Когда я запрошу новый контейнер IServiceD из контейнера, я хочу, чтобы тот же экземпляр IServiceA был введен в IServiceD и его зависимости IServiceB и IServiceC. Тем не менее, я не ищу глобальную область синглов. В следующий раз, когда я попрошу экземпляр IServiceD, должен создать с новым экземпляром IServiceA (я знаю, что вы не можете создать экземпляр интерфейса, но я думаю, что вы поняли суть).

Для иллюстрации; когда я прошу autofac контейнер в течение IServiceD я хочу следующее произойдет:

public class ServiceD : IServiceD 
{ 
    public ServiceD(IServiceA sa, IServiceB sb, IServiceC sc) 
    { 
     // SA should be the same (but it is not) 
     sa.GetHashCode() == sb.GetServiceA().GetHashCode() == sc.GetServiceA().GetHashCode() 
    } 
} 

Пожалуйста, обратите внимание, что метод GetServiceA() включается только для иллюстрации моей точки.

Так что да, я предполагаю, что я ищу какой-нибудь способ, чтобы сказать autofac, что, когда он решает IServiceD он должен создать синглтон из ServiceA, но только для сферы конструктора ServiceD «s.

Прямо сейчас, я использую autofacs поддержку делегатов заводов и попросить:

public ServiceD(IServiceA sa, Func<IServiceA, IServiceB> fb, Func<IServiceA, IServiceC> fc) : IServiceD 
{ 
    var sb = fb(sa); // Manually inject the same instance of ServiceA 
    var sc = fc(sa); // Manually inject the same instance of ServiceA 

    // ServiceA is now the same instance 
    sa.GetHashCode() == sb.GetServiceA().GetHashCode() == sc.GetServiceA().GetHashCode() 
} 

Это заставляет меня идти, но у меня есть чувство, что это может быть сделано лучше, - вот почему я обращаюсь к экспертов.

Заранее благодарен.

ответ

2

InstancePerLifetimeScope может удовлетворить ваши потребности. Он позволяет иметь один экземпляр на всю продолжительность жизни.

builder.RegisterType<ServiceA>().As<IServiceA>().InstancePerLifetimeScope(); 
builder.RegisterType<ServiceB>().As<IServiceB>().InstancePerLifetimeScope(); 
builder.RegisterType<ServiceC>().As<IServiceC>().InstancePerLifetimeScope(); 
builder.RegisterType<ServiceD>().As<IServiceD>().InstancePerLifetimeScope(); 

Затем каждый раз, когда вы решить IServiceD в новой области вы будете иметь один экземпляр IServiceA

using (ILifetimeScope scope = container.BeginLifetimeScope()) 
{ 
    // only an instance of IServiceA will be created for this scope 
    scope.Resolve<IServiceD>(); 
} 

Если вы не можете создать новую ILifetimeScope вы можете использовать Owned<T> тип, который легкий образ жизни.

using (Owned<IServiceD> ownedD = container.Resolve<Owned<IServiceD>>()) 
{ 
    IServiceD serviceD = ownedD.Value;     
} 

Каждый раз, когда вы решить Owned<IserviceD> новый ILifetimeScope будет создан, и только будет создан единый IServiceA.

Если этого недостаточно, вы можете играть с InstancePerMatchingLifetimeScope, но это сделает ваш код и регистрацию довольно трудным для чтения и отладки. InstancePerLifetimeScope должно быть достаточно.

Другим решением является использование такого вида регистрации.

builder.Register(ctx => 
{ 
    IServiceA serviceA = ctx.Resolve<IServiceA>(); 
    IServiceB serviceB = ctx.Resolve<IServiceB>(TypedParameter.From(serviceA)); 
    IServiceC serviceC = ctx.Resolve<IServiceC>(TypedParameter.From(serviceA)); 
    IServiceD serviceD = ctx.Resolve<IServiceD>(TypedParameter.From(serviceA), TypedParameter.From(serviceB), TypedParameter.From(serviceC)); 
    return serviceD; 
}).As<IServiceD>(); 

Но на самом деле это не изящно.

+0

Привет, Кирилл, жаль, что принял ваш ответ этим поздно. Я ценю ваш вклад. Ваш совет относительно 'InstancePerLifetimeScope()' был тем, который мне нужно было продолжить. Благодарю. –

Смежные вопросы