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
名称,您可以使用 Keyed 与 enumeration
s 一起使用。
AutoFac 通过依赖 IEnumerable<T>
直接支持这一点。当它看到 IEnumerable
时,它将 return 一个满足接口 T
.
的所有注册类型的集合
在您的情况下,将 LogsOutput
和 ConsoleOutput
注册为 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.
我是 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
名称,您可以使用 Keyed 与 enumeration
s 一起使用。
AutoFac 通过依赖 IEnumerable<T>
直接支持这一点。当它看到 IEnumerable
时,它将 return 一个满足接口 T
.
在您的情况下,将 LogsOutput
和 ConsoleOutput
注册为 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.