Autofac 如何帮助您同时在现有 class 中注入 class/interface 的多个实例

How Autofac helps You to inject multiple instances of a class/interface in an existing class at the same time

我是 Autofac 的新手,还不了解所有的潜力。 让我们以网站文档中的快速 autofac 教程中考虑的示例为例。 (https://autofac.readthedocs.io/en/latest/getting-started/index.html)

using System;

namespace DemoApp
{

 public interface IOutput
 {
   void Write(string content);
 }

 public class ConsoleOutput : IOutput
 {
    public void Write(string content)
    {
        Console.WriteLine(content);
    }
  }

  public interface IDateWriter
  {
     void WriteDate();
  }

  public class TodayWriter : IDateWriter
  {
     private IOutput _output;
     public TodayWriter(IOutput output)
     {
         this._output = output;
     }

     public void WriteDate()
     {
         this._output.Write(DateTime.Today.ToShortDateString());
     }
 }
}

Autofac 胶水如下所示:

using System;
using Autofac;

namespace DemoApp
{
   public class Program
   {
     private static IContainer Container { get; set; }

   static void Main(string[] args)
   {
       var builder = new ContainerBuilder();
       builder.RegisterType<ConsoleOutput>().As<IOutput>();
       builder.RegisterType<TodayWriter>().As<IDateWriter>();
       Container = builder.Build();

       WriteDate();
   }
  }
}


public static void WriteDate()
 {
  // Create the scope, resolve your IDateWriter,
  // use it, then dispose of the scope.
  using (var scope = Container.BeginLifetimeScope())
  {
    var writer = scope.Resolve<IDateWriter>();
    writer.WriteDate();
  }
}

这个程序的目的只是在控制台上打印日期时间。现在假设我不仅要在控制台中而且要在日志中打印日期时间。为此,我想创建另一个 class 具有如下接口 IOutput :

public class LogsOutput : IOutput
{
    public void Write(string content)
    {
        // write content to a log file here
    }
 }

这是一个纯粹的例子。我想将这个例子扩展到一个更大的问题。 现在 Autofac 胶水代码应该是什么样子的?为了让代码同时执行 ConsoleOutput classe 和 LogsOutput class 并将输出打印到控制台和日志文件 ?

是否可以使用 Autofac 实现此目的,或者这不是 autofac 的行为? 我可能希望能够使用 IOutput 接口添加数百个 classes。如何使用 Autofac 实现这一目标?

创建新的 IOutput 类型后,

首先你需要在容器中注册它,使用Named

var builder = new ContainerBuilder();
builder.RegisterType<ConsoleOutput>().Named<IOutput>("console");
builder.RegisterType<LogsOutput>().Named<IOutput>("logs");
builder.RegisterType<TodayWriter>().As<IDateWriter>();
Container = builder.Build();

然后,在 WriteDate() 方法中,您通过使用 name 参数调用 ResolveNamed 方法来指定要使用的 Ioutput 类型,这是在注册中指定的名称类型:

public static void WriteDate()
 {
  // Create the scope, resolve your IDateWriter,
  // use it, then dispose of the scope.
  using (var scope = Container.BeginLifetimeScope())
  {
    var writer = scope.ResolveNamed<IDateWriter>("console"); // for console output
    //var writer = scope.ResolveNamed<IDateWriter>("logs"); // for logs output
    writer.WriteDate();
  }
}

注意:如果您不使用 string 名称,您可以使用 Keyedenumerations 一起使用。

AutoFac 通过依赖 IEnumerable<T> 直接支持这一点。当它看到 IEnumerable 时,它将 return 一个满足接口 T.

的所有注册类型的集合

在您的情况下,将 LogsOutputConsoleOutput 注册为 IOutput,并解析 IEnumerable<IOutput>,以同时获得两者注册服务。


可以找到更多详细信息 here

Dependencies of an enumerable type provide multiple implementations of the same service (interface). This is helpful in cases like message handlers, where a message comes in and more than one handler is registered to process the message.