2016-04-24 1 views
5

мне интересно, есть ли побочный эффект регистрации контейнера внутри себяРегистрация Контейнер Сама Использование Autofac

IContainer container; 
ContainerBuilder builder = new ContainerBuilder(); 
container = builder.Build(); 
builder.RegisterInstance(container).As<IContainer>(); 

и использовать его как этот

builder.RegisterType<IManagmentServiceImp>().As<ManagmentServiceImp>() 
    .WithParameter(new ResolvedParameter(
      (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container", 
      (pi, ctx) => container 
)); 

или он будет работать даже.

ответ

10

Ваш код небезопасен, поскольку вы регистрируете экземпляр до его инициализации.

Если у вас есть доступ к контейнеру внутри компонента (это не очень хорошая идея), вы можете иметь зависимость от ILifetimeScope, которые имеют методы Resolve.

public class ManagmentServiceImp 
{ 
    public ManagmentServiceImp(ILifetimeScope scope) 
    { 
    } 
} 

ILifetimeScope автоматически регистрируется в Autofac вам не нужно, чтобы добавить регистрацию для него.

См. Controlling Scope and Lifetime от Autofac документация для получения дополнительной информации.

Кстати, это неправда, чтобы иметь зависимость от вашего контейнера IoC. Похоже, вы используете Service Locator анти-шаблон. Если вам нужен контейнер для ленивых зависимости нагрузки, вы можете использовать композицию с Func<T> или Lazy<T>

public class ManagmentServiceImp 
{ 
    public ManagmentServiceImp(Lazy<MyService> myService) 
    { 
     this._myService = myService; 
    } 

    private readonly Lazy<MyService> _myService; 
} 

В этом случае MyService будет создан при первом доступе его.

См. Implicit Relationship от Autofac документация для получения дополнительной информации.

1

Поскольку вам необходимо предоставить экземпляр контейнера builder.RegisterInstance(), вам необходимо инициализировать его ПЕРЕД прохождением его в качестве аргумента, который вы в настоящее время не выполняете. Однако, если вы структурируете построитель контейнеров для создания ПОСЛЕ регистрации (и инициализации контейнера), вы можете успешно разрешить экземпляр контейнера в своем классе.

Обратите внимание, что это, безусловно, запах дизайна в Dependency Injection, и вы абсолютно не должны этого делать. Ваш контейнер/ядро ​​должен существовать только на верхнем уровне вашего графа объектов. Если вы начнете вводить свой контейнер, вы почти наверняка будете на пути к анти-шаблону Locator.

void Main() 
{ 
    IContainer container = new ContainerBuilder().Build(); 
    ContainerBuilder builder = new ContainerBuilder(); 

    builder.RegisterInstance(container).As<IContainer>(); 

    builder.RegisterType<ManagementServiceImp>().As<IManagmentServiceImp>() 
     .WithParameter(new ResolvedParameter(
      (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container", 
      (pi, ctx) => container 
    )); 

    container = builder.Build(); 
    var instance = container.Resolve<IManagmentServiceImp>(); 
} 

public class ManagementServiceImp : IManagmentServiceImp 
{ 
    private IContainer _container; 

    public ManagementServiceImp(IContainer Container) 
    { 
     _container = Container; 
     _container.Dump(); 
    } 
} 

public interface IManagmentServiceImp { } 
+0

@torvin Каким образом контейнер не настроенное и каким образом это не решает потребность OP еще? –

+0

жаль, что я случайно удалил свой комментарий.Это было «Это неправильно, он зарегистрирует неконфигурированный контейнер» – torvin

+0

@torvin, вы все еще не объяснили, как это не соответствует потребностям OP. –

0

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

Ваш код обслуживания ничего не должен знать о IOC IMO.

+3

Хотя я абсолютно уверен в том, что вы используете контейнер во всем, кроме регистрации, есть ситуации, которые я мог бы подумать о том, какой спрос на немного уродства. Лично я думаю, что вы не должны давать такую ​​обратную связь, не предлагая альтернативу для вопрошающего ... – DotBert

1

Вы можете использовать этот метод расширения:

public static void RegisterSelf(this ContainerBuilder builder) 
{ 
    IContainer container = null; 
    builder.Register(c => container).AsSelf(); 
    builder.RegisterBuildCallback(c => container = c); 
} 

использовать его как это: builder.RegisterSelf();

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