如何使用Autofac在运行时根据用户选择注入对应Logger类
问题
我有一个简易应用,通过依赖注入实现两种日志记录方式,所有Logger类都派生自ILogger接口。LoggerFactory类负责决定为TheAmazingApp返回哪个具体Logger,但当前是在LoggerFactory中手动实例化Logger。现在需要实现:如何使用Autofac在运行时根据用户选择加载正确的Logger类?
以下是原可编译控制台应用代码:
原代码文件
Main.cs
using Autofac; namespace DepInjection { internal class Program { static void Main(string[] args) { var Builder = new ContainerBuilder(); //Start configure Builder.RegisterType<TheAmazingApp>(); Builder.RegisterType<LoggerFactory>(); Builder.RegisterType<NormalLogger>().As<ILogger>(); Builder.RegisterType<VerboseLogger>().As<ILogger>(); //End configure var Container = Builder.Build(); using (var scope = Container.BeginLifetimeScope()) { scope.Resolve<TheAmazingApp>().AmazeUs(); } } } }
TheAmazingApp.cs
namespace DepInjection { public class TheAmazingApp { private ILogger _logger; public TheAmazingApp() { _logger = LoggerFactory.GetLogger(); } public void AmazeUs() => _logger.Logger(); } }
ILogger.cs
namespace DepInjection { public interface ILogger { public void Logger(); } }
VerboseLogger.cs
namespace DepInjection { public class VerboseLogger : ILogger { public void Logger() => Console.WriteLine("Verbose Log"); } }
NormalLogger.cs
namespace DepInjection { public class NormalLogger : ILogger { public void Logger() => Console.WriteLine("Normal Log"); } }
LoggerFactory.cs
namespace DepInjection { public class LoggerFactory { private static string? _choice; public static ILogger GetLogger() { //emulates the result of a user choice at run time _choice = "other"; //...but how do I implement this using a dependency injector? return _choice == "1" ? new NormalLogger() : new VerboseLogger(); } } }
解决方案
要实现Autofac运行时动态选择Logger,需要重构代码以符合依赖注入原则,具体步骤如下:
- 给每个Logger实现添加命名标识,让Autofac能区分不同的
ILogger实例 - 重构
LoggerFactory,移除静态逻辑,通过注入Autofac容器上下文来解析Logger - 修改
TheAmazingApp,通过构造注入获取Logger,避免直接调用静态方法 - 在运行时获取用户选择,动态匹配对应的Logger
修改后的完整代码
Main.cs
using Autofac; namespace DepInjection { internal class Program { static void Main(string[] args) { // 获取用户选择 Console.WriteLine("请选择日志类型:1=NormalLogger,其他=VerboseLogger"); var userChoice = Console.ReadLine(); var builder = new ContainerBuilder(); // 注册带命名的Logger实现 builder.RegisterType<NormalLogger>().Named<ILogger>("normal"); builder.RegisterType<VerboseLogger>().Named<ILogger>("verbose"); // 注册LoggerFactory和应用类 builder.RegisterType<LoggerFactory>(); builder.RegisterType<TheAmazingApp>(); var container = builder.Build(); using (var scope = container.BeginLifetimeScope()) { var loggerFactory = scope.Resolve<LoggerFactory>(); var app = new TheAmazingApp(loggerFactory.GetLogger(userChoice)); app.AmazeUs(); } } } }
TheAmazingApp.cs
namespace DepInjection { public class TheAmazingApp { private readonly ILogger _logger; // 构造注入Logger,符合依赖注入原则 public TheAmazingApp(ILogger logger) { _logger = logger; } public void AmazeUs() => _logger.Logger(); } }
LoggerFactory.cs
using Autofac; namespace DepInjection { public class LoggerFactory { private readonly IComponentContext _componentContext; // 构造注入Autofac容器上下文,用于解析服务 public LoggerFactory(IComponentContext componentContext) { _componentContext = componentContext; } public ILogger GetLogger(string? userChoice) { // 根据用户选择解析对应的命名Logger return userChoice == "1" ? _componentContext.ResolveNamed<ILogger>("normal") : _componentContext.ResolveNamed<ILogger>("verbose"); } } }
其他文件(ILogger.cs、NormalLogger.cs、VerboseLogger.cs)保持不变
说明
- 通过命名服务机制,Autofac可以精准区分不同的
ILogger实现,避免手动实例化类 LoggerFactory不再直接创建Logger,而是通过Autofac容器上下文解析,完全遵循控制反转原则- 用户选择在运行时动态获取,实现了需求中的运行时切换逻辑
内容的提问来源于stack exchange,提问作者Valmont
相关产品推荐
相关产品推荐

