C# Autofac-使用当前类中的构造函数参数初始化对象,与生成器所在的类不同

C# Autofac-使用当前类中的构造函数参数初始化对象,与生成器所在的类不同,c#,autofac,C#,Autofac,在下面的代码中,为了清晰起见,在第二个类中使用config和monitor非常简单。如何创建/注册/解析计时器?它似乎不能在第一个类中完成,因为它需要来自第二个类的构造函数参数值,但是如果我理解正确,那么所有寄存器/解析都应该在第一个类中进行 using System; using System.ServiceProcess; using System.Threading; using Autofac; namespace MyServiceApp { static class My

在下面的代码中,为了清晰起见,在第二个类中使用config和monitor非常简单。如何创建/注册/解析计时器?它似乎不能在第一个类中完成,因为它需要来自第二个类的构造函数参数值,但是如果我理解正确,那么所有寄存器/解析都应该在第一个类中进行

using System;
using System.ServiceProcess;
using System.Threading;

using Autofac;

namespace MyServiceApp
{
    static class MyServiceAppMain
    {
        static void Main()
        {
            using (var container = InitContainer())
            {
                    container.Resolve<MyService>().Start();
            }
        }

        private static IContainer InitContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Configuration>().As<IConfiguration>();
            builder.RegisterType<ServicesMonitor>();
            builder.RegisterType<MyService>();

            IContainer container = 
                builder.Build(Autofac.Builder.ContainerBuildOptions.None);

            return container;
        }
    }

    public partial class MyService : ServiceBase, IMyService
    {
        private Timer _processTimer;
        private int _intervalSize;
        private IConfiguration _config;
        private ServicesMonitor _monitor;

        public MyService(IConfiguration config, ServicesMonitor monitor)
        {
            InitializeComponent();

            _config = config;
            _monitor = monitor;

            _config.ReadAppConfig();
        }

        public void Start()
        {
            OnStart(null);
        }

        protected override void OnStart(string[] args)
        {
            _intervalSize = _config.IntervalMinutes * (60 * 1000);

            _processTimer = 
                new Timer(ProcessTimer_Elapsed, null, Timeout.Infinite, _intervalSize);
        }

        private void ProcessTimer_Elapsed(object sender)
        {
                _processTimer.Change(Timeout.Infinite, _intervalSize);
        }
    }
}
使用系统;
使用System.ServiceProcess;
使用系统线程;
使用Autofac;
命名空间MyServiceApp
{
静态类MyServiceAppMain
{
静态void Main()
{
使用(var container=InitContainer())
{
container.Resolve().Start();
}
}
私有静态IContainer InitContainer()
{
var builder=new ContainerBuilder();
builder.RegisterType().As();
RegisterType();
RegisterType();
i集装箱=
builder.Build(Autofac.builder.ContainerBuildOptions.None);
返回容器;
}
}
公共部分类MyService:ServiceBase,IMyService
{
专用定时器_processTimer;
私人int_intervalize;
私有IConfiguration\u config;
私人服务监视器(monitor);;
公共MyService(IConfiguration配置、ServicesMonitor监视器)
{
初始化组件();
_config=config;
_监视器=监视器;
_config.ReadAppConfig();
}
公开作废开始()
{
OnStart(空);
}
启动时受保护的覆盖无效(字符串[]args)
{
_intervalize=_config.IntervalMinutes*(60*1000);
_processTimer=
新计时器(ProcessTimer\u已用、null、Timeout.Infinite、\u Intervalize);
}
私有void ProcessTimer_已过(对象发送方)
{
_processTimer.Change(Timeout.Infinite,_intervalize);
}
}
}

我假设您的目标是可测试性,或者以某种方式抽象出
计时器
对象的创建。由于
Timer
实际上没有实现接口,因此您有几个选项

但是,您正在修改回调中的
计时器,这使得您的情况更加复杂。从这个例子来看,看起来你实际上并没有做任何改变-你用一个特定的到期时间和回调时间设置了原始计时器。。。然后再把它设置为相同的东西

选项一:做你已经在做的事情

控制反转在有意义的地方是很好的,但是你不能真的“伪造”一个计时器或者“替换”一个计时器来实现其他的实现。如前所述,它没有实现任何
ITimer
接口或类似的东西

如果你不需要把它换掉。。。就让它发生吧。在测试过程中交换配置值和内容,使其更适合您的测试,并称之为良好

选项二:包装计时器

如果你需要在你的类之外创建它,你需要用。。。某物然后你可以换掉包装纸

由于您正在修改
计时器本身,因此需要在中封装一点该功能

public class SelfAdjustingTimer
{
  public Timer Timer { get; protected set; }
  public int Interval { get; private set; }
  public SelfAdjustingTimer(int interval)
  {
    this.Interval = interval;
    this.Timer = new Timer(Callback, null, Timeout.Infinite, interval);
  }
  private void Callback(object sender)
  {
    this.Timer.Change(Timeout.Infinite, this.Interval);
  }
}
您甚至可以添加一个事件或在回调过程中引发的事件,如果您需要知道它何时发生或基于此进行一些工作的话

选项三:疯狂的Lambda处理器

它可能会变得非常复杂,但您知道如何使用lambda表达式生成事件处理程序,如

someObj.TheEvent += (sender, args) => { /* Do Work */ };
假设您可以找到一种使用lambda表达式构建动态自引用回调的方法,并以这种方式创建计时器回调。我以前做过类似的事情,而且。。。这让人有点困惑。这就像lambdas生成lambdas一样,需要一段时间才能弄清楚(这就是为什么我不在这里把它交给您)

如果不必修改回调中的计时器

…那么你有更多的选择。你可以

  • 创建一个
    ITimerFactory
    ,让它根据配置为您生成计时器。将其注入到类中并使用它。(
    ITimerFactory
    及其实现是您必须创建的东西。它们不存在。)
  • 创建一个
    TimerBase
    和一个
    TimerRapper
    ,就像他们在ASP.NET中使用
    HttpContextBase
    HttpContextWrapper
    所做的那样。将
    TimerBase
    注入类中,而不是更新
    计时器。对于
    TimerBase
    的DI注册,您可以在这里查找配置值并设置真正的
    计时器
……等等。所有的选项都涉及到抽象出具体的
Timer
对象的概念,因为它没有实现任何接口,甚至不能从中派生


如果是我。。。我可能会做你正在做的事情,尽可能地将代码隔离到一个较小的服务类中,这个服务类可以与
Timer
进行所有交互,并且有更好的方法可以模仿(例如,用一些东西包装
Timer
),然后尽可能多地用包装器进行测试。

谢谢,特拉维斯。你的评论“如果你不必把它换掉……就让它发生吧。”让我直截了当——我已经看不见树木了。我希望将来我仍然会面临需要将参数传递给构造函数的问题(没有回调——计时器是一个令人困惑的例子),但当我谈到它时,我会跨越这座桥。