2016-04-24 99 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();