是的,到处传递容器是一种反模式。
你可以通过使用这样的工厂来避免它:
(注意:此答案中的所有代码都未经测试,我是在没有 Visual Studio 的机器上的文本编辑器中编写的)
public interface IServiceHelperFactory
{
IServiceHelper CreateServiceHelper(string serviceName);
}
public class ServiceHelperFactory : IServiceHelperFactory
{
private IContainer container;
public ServiceHelperFactory(IContainer container)
{
this.container = container;
}
public IServiceHelper CreateServiceHelper(string serviceName)
{
return container.Resolve<ServiceHelper>(new NamedParameter("serviceName", serviceName));
}
}
在启动时,您在 Autofac 中注册 ServiceHelperFactory,就像其他所有内容一样:
builder.RegisterType<ServiceHelperFactory>().As<IServiceHelperFactory>();
然后,当您在其他地方需要ServiceHelper 时,您可以通过构造函数注入获取工厂:
public class SomeClass : ISomeClass
{
private IServiceHelperFactory factory;
public SomeClass(IServiceHelperFactory factory)
{
this.factory = factory;
}
public void ThisMethodCreatesTheServiceHelper()
{
var helper = this.factory.CreateServiceHelper("some service name");
}
}
通过使用 Autofac 的构造函数注入来创建工厂本身,您可以确保工厂知道容器,而不必自己传递容器。
我承认,乍一看,这个解决方案与直接传递容器并没有太大区别。但优点是您的应用仍然与容器解耦 - 容器已知的唯一位置(启动除外)是在工厂内部。
编辑:
好的,我忘记了。正如我上面所说,我是在没有 Visual Studio 的机器上编写的,所以我无法测试我的示例代码。
现在我看了你的评论,我记得我在使用 Autofac 并尝试注册容器本身时遇到了类似的问题。
我的问题是我需要在构建器中注册容器。
但是要让容器实例注册,我需要调用 builder.Build()... 来创建容器,这意味着之后我无法在构建器中注册东西。
我不记得我收到的错误消息,但我猜你现在也有同样的问题。
我找到的解决方案是创建第二个构建器,在那里注册容器,然后使用第二个构建器更新唯一的容器。
这是我的一个开源项目的工作代码:
On startup, I register the container::
var builder = new ContainerBuilder();
// register stuff here
var container = builder.Build();
// register the container
var builder2 = new ContainerBuilder();
builder2.RegisterInstance<IContainer>(container);
builder2.Update(container);
...然后使用by a WindowService to create new WPF windows:
public class WindowService : IWindowService
{
private readonly IContainer container;
public WindowService(IContainer container)
{
this.container = container;
}
public T GetWindow<T>() where T : MetroWindow
{
return (T)this.container.Resolve<T>();
}
}