gpt4 book ai didi

c# - Autofac - 无需传递容器即可解析运行时参数

转载 作者:IT王子 更新时间:2023-10-29 04:34:18 25 4
gpt4 key购买 nike

我有一个更简单的“ServiceHelper”类,它在构造函数中有两个参数:

public ServiceHelper(ILogger<ServiceHelper> log, string serviceName)

(Autofac 提供的 NLog 的 ILogger 通用包装器,serviceName 是我需要在运行时提供的用于控制的 Windows 服务的名称。)

我无法思考如何使用 Autofac 在运行时创建此类的新实例并传入不同的服务名称。这样的事情当然行不通,因为我需要在运行时指定不同的服务名称:

builder.RegisterType<ServiceHelper>().As<IServiceHelper>().WithParameter(new NamedParameter("serviceName", null)).InstancePerDependency();

据我所知,传递容器并正确地手动调用 Resolve 是一个坏习惯(AutoFac 警告的服务定位器“反模式”),是吗?如果我那样做,那么我可以做到

container.Resolve<ServiceHelper>(new NamedParameter("serviceName", "some service name"));

但即便如此,我也不太确定如何让 Autofac 将容器注入(inject)到类中,它只需要准确地注册自己,就像这样?然后让我的类在其构造函数中需要一个 IContainer 吗? (这是在使用构造函数注入(inject)的 C# 服务中)

builder.RegisterType<Container>().As<IContainer>().InstancePerDependency();

我也读过有关委托(delegate)工厂的内容,但这似乎并不能避免必须传递容器。

实际上,我的大多数使用 ServiceHelper 的类只需要 1 或 2 个 ServiceHelper 用于特定的服务名称,所以我并没有用意想不到的 serviceName 参数赚取数千,这只是让我有点头疼。

最佳答案

是的,到处传递容器是一种反模式。

你可以通过使用这样的工厂来避免它:

(注意:此答案中的所有代码都未经测试,我是在没有 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 时,您可以通过构造函数注入(inject)获取工厂:

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 的构造函数注入(inject)创建工厂本身,您可以确保工厂知道容器,而不必自己传递容器。

我承认,乍一看,这个解决方案与直接传递容器并没有太大区别。但优点是您的应用程序仍然与容器分离 - 容器唯一已知的地方(启动除外)是在工厂内部。


编辑:

好吧,我忘了。正如我上面所说,我是在没有 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>();
}
}

关于c# - Autofac - 无需传递容器即可解析运行时参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22259722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com