You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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,需要重构代码以符合依赖注入原则,具体步骤如下:

  1. 给每个Logger实现添加命名标识,让Autofac能区分不同的ILogger实例
  2. 重构LoggerFactory,移除静态逻辑,通过注入Autofac容器上下文来解析Logger
  3. 修改TheAmazingApp,通过构造注入获取Logger,避免直接调用静态方法
  4. 在运行时获取用户选择,动态匹配对应的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 03:42:14