从你的 sn-p 中,你有:
- 一个名为
SerialPortController 的ISerialPortController 实现在应用程序中注册为单个实例。这意味着它将在 Autofac 容器的生命周期内存在,这通常也是应用程序的生命周期。
-
SerialPortController 使用的值来自ISettingsModel。该模型中的设置可能会在应用程序的过程中发生变化,当它们发生变化时,SerialPortController 需要开始使用新值。
我将从回答一个简单的问题开始:没有办法在 Autofac 中重新初始化单例。单例的优点和缺点是......它是一个单例。一旦建成,它就建成了。您必须删除整个容器并重新构建它才能重新构建单例。
还有其他方法可以解决该问题,但实际上并不需要重新初始化单例。
选项 1:不要将控制器设为单例
不要将控制器设为单例,而是将其设为InstancePerDependency。它使用的设置只有在单个实例还活着时才会保留。
您可能出于某些原因希望它成为单例,例如创建它的成本可能很高,或者它可能充当资源池之类的东西。这很酷,还有更多选择。这只是最简单的答案。
选项 2:将端口参数更改为更动态的参数
我的意思是,不是让SerialPortController 采用文字端口号,而是采用一个用于检索端口号的函数。
例如,假设ISettingsModel 自动始终具有最新值。如果您向单身人士ISettingsModel 询问ConveyorSerialPort,它总是 是最新的。您可以将控制器更改为采用ISettingsModel。
public class SerialPortController
{
private readonly ISettingsModel _model;
public SerialPortController(ISettingsModel model)
{
this._model = model;
}
public void DoSomething()
{
// port will always be up to date.
var port = this._model.ConveyorSerialPort;
this.CommunicateOn(port);
}
}
在这种情况下,由ISettingsModel 来保持其值的新鲜度,但只要发生这种情况,控制器就可以是单例(理想情况下,ISettingsModel 也可以是单例,否则您将拥有一个captive dependency situation.
但是假设每次解析时都会生成ISettingsModel。为了获得新的设置,您必须获得一个新的ISettingsModel。没关系,你也可以用 Autofac 做到这一点,使用 Func<T>:
public class SerialPortController
{
private readonly Func<ISettingsModel> _modelFactory;
public SerialPortController(Func<ISettingsModel> modelFactory)
{
this._modelFactory = modelFactory;
}
public void DoSomething()
{
// port will always be up to date.
var port = this._modelFactory().ConveyorSerialPort;
this.CommunicateOn(port);
}
}
自动生成的Func<ISettingsModel> 将从容器中解析出一个全新的ISettingsModel。由于您的控制器是单例的,因此它将来自容器的根目录。 如果ISettingsModel 是一次性的,请小心。 如果它是一次性的 (IDisposable),那么 Autofac 会一直保留它,直到容器被丢弃,从而导致内存泄漏。 There are ways to work around this, too. 但这可能会开始变得有点复杂,我想给你一个有用的答案。文档非常好(如果我自己这么说的话)并且有很多例子。它很长,但值得花时间检查一下。