2016-04-24 102 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 LifetimeAutofac文档获取更多信息。

顺便说一句,依赖于你的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 RelationshipAutofac文档获取更多信息。

1

由于您需要将容器的实例提供给builder.RegisterInstance(),因此您需要在将其作为参数传递给它之前对其进行初始化,而您目前没有这样做。但是,如果您构建了容器构建器以构建AFTER注册(和容器初始化),则可以成功解析您的类中的容器实例。

请注意,这绝对是一种依赖注入的设计气味,你绝对不应该这样做。您的容器/内核应该只存在于对象图的顶层。如果您开始注射您的容器,几乎可以肯定您正在前往服务定位器反模式。

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();