【问题标题】:How do you change a value in an object that has a long lifetime in Autofac?如何更改 Autofac 中具有较长生命周期的对象中的值?
【发布时间】:2019-02-19 08:33:38
【问题描述】:

现有应用程序基于 MVVM Light 并使用 autofac 容器创建对象。在应用程序的生命周期中,需要使用新参数重建已创建的对象。我对 autofac 的经验较少

例子:

 containerBuilder.RegisterType<SerialPortController>().Named<ISerialPortController>("ConveyorController").WithParameter(
            new ResolvedParameter(
                (pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "portName",
                (pi, ctx) => ctx.Resolve<ISettingsModel>().ConveyorSerialPort)).SingleInstance();

例如,“portName”已更改。 我没有看到一个好的解决方案。有人体验过吗?

【问题讨论】:

  • portName 是参数的名称,在对象的生命周期内如何改变?
  • @tomsky 我怀疑 OP 的意思是解析的参数值(即ctx.Resolve&lt;ISettingsModel&gt;().ConveyorSerialPort
  • 是的。你说的对。我的意思是参数的值:)

标签: c# autofac


【解决方案1】:

从你的 sn-p 中,你有:

  • 一个名为SerialPortControllerISerialPortController 实现在应用程序中注册为单个实例。这意味着它将在 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&lt;T&gt;:

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&lt;ISettingsModel&gt; 将从容器中解析出一个全新的ISettingsModel。由于您的控制器是单例的,因此它将来自容器的根目录。 如果ISettingsModel 是一次性的,请小心。 如果它是一次性的 (IDisposable),那么 Autofac 会一直保留它,直到容器被丢弃,从而导致内存泄漏。 There are ways to work around this, too. 但这可能会开始变得有点复杂,我想给你一个有用的答案。文档非常好(如果我自己这么说的话)并且有很多例子。它很长,但值得花时间检查一下。

【讨论】:

  • 对于像你这样的好答案,我希望 stackoverflow 会添加一个 +100 投票按钮
  • @Twan 如果您喜欢它,请接受它作为答案,以便我获得信用。谢谢!
  • 很好的解释。加 1!
  • 谢谢。如果@Twan 可以回来接受我的回答,那么从信用的角度来看,这将非常有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-20
  • 1970-01-01
  • 1970-01-01
  • 2012-11-24
相关资源
最近更新 更多