Autofac 通用接口工厂

n0r*_*0rd 4 c# generics autofac

ILoggerFactory在 Autofac 容器中注册了一个实现。我希望能够使用 Autofac 注册以下类并能够实例化它:

public class Test
{
    public Test(ILogger<Test> logger)
    {
        logger.LogInformation("Works!");
    }
}
Run Code Online (Sandbox Code Playgroud)

为此,我需要能够“教” Autofac 生成实现ILogger<T>任何类的实例T。有一个ILoggerFactory扩展方法CreateLogger<T>(),并CreateLogger(Type)认为能够生产所需类型的实例,但我不能换我围绕着如何使Autofac打电话给他们的头。

如果我想要非泛型ILogger,我会写

containerBuilder.Register(c => c.Resolve<ILoggerFactory>().CreateLogger("default"))
Run Code Online (Sandbox Code Playgroud)

但我不确定如何处理通用的。任何指针?

更新:阅读更多文档后,我想出了这个:

public class LoggingModule: Autofac.Module
{
    private readonly MethodInfo mi;

    public LoggingModule()
    {
        this.mi = typeof(LoggerFactoryExtensions)
            .GetMethod(nameof(LoggerFactoryExtensions.CreateLogger), new[] { typeof(ILoggerFactory) });
    }

    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        registration.Preparing += OnComponentPreparing;
    }

    private void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
        e.Parameters = e.Parameters.Union(
            new[]
            {
                new ResolvedParameter(
                    (p, i) => IsGenericLoggerParameter(p.ParameterType),
                    (p, i) => CreateLogger(this.mi, p.ParameterType, i.Resolve<ILoggerFactory>())
                    )
            });
    }

    private static bool IsGenericLoggerParameter(Type parameterType)
    {
        return parameterType.IsGenericType && parameterType.GetGenericTypeDefinition() == typeof(ILogger<>);
    }

    private static object CreateLogger(MethodInfo mi, Type typeArg, ILoggerFactory loggerFactory)
    {
        Type genericArg = typeArg.GetGenericArguments().First();
        MethodInfo generic = mi.MakeGenericMethod(new[] { genericArg });
        return generic.Invoke(null, new[] { loggerFactory });
    }
}
Run Code Online (Sandbox Code Playgroud)

进而:

        containerBuilder.RegisterType<Test>().AsSelf();
        containerBuilder.RegisterModule<LoggingModule>();
        var container = containerBuilder.Build();
        var test = container.Resolve<Test>();
Run Code Online (Sandbox Code Playgroud)

作品。问题是我不完全理解它是如何工作的(更重要的是,它是如何崩溃的),所以我仍在寻找更优雅和/或更易于理解的解决方案。

n0r*_*0rd 6

我找到了一个简单的答案,但仅适用于ILogger<T>来自Microsoft.Extensions.Logging包的:使用ServiceCollection来自Microsoft.Extensions.DependencyInjection包的:

        IServiceCollection services = new ServiceCollection();
        services.AddLogging(); // all the magic happens here
        // set up other services 
        var builder = new ContainerBuilder();
        builder.Populate(services); // from the Autofac.Extensions.DependencyInjection package
        IContainer container = builder.Build();
        Test t = container.Resolve<Test>();
Run Code Online (Sandbox Code Playgroud)