【问题标题】:Autofac resolve Generic type with constructor parameters at run timeAutofac 在运行时使用构造函数参数解析泛型类型
【发布时间】:2019-02-28 22:47:54
【问题描述】:

我有一个通用类 Logger<TProvider> where TProvider : ILogProvider,我想为它配置 Autofac 的依赖注入。

这个类也有一个构造函数:

public Logger(LogType loggerType)

目前是这样使用的:

var logger = new Logger<Log4NetLogProvider>(LogType.CMS);

我想知道这是否可能是依赖注入,或者由于需要类型/构造函数参数而无法实现?

我知道RegisterGeneric 方法,例如:

builder.RegisterGeneric(typeof(Logger<>)).AsSelf()

我想知道如何告诉 autofac 传入了哪个 TProvider 并提供构造函数参数 LogType?或者这不是 DI 的理想选择?

【问题讨论】:

  • 您是否希望使用 LogType.CMS 构造的记录器可以与使用 LogType.Foo 构造的记录器互换使用?如果不是,那么您的设计应该使用单独的接口进行通信——ICmsLogger 和 IFooLogger。然后,您的服务将依赖特定的接口。
  • @MikeHixson - 这是一个我没想到的好主意
  • @MikeHixson 这可行,但我必须针对记录器类指定所有接口类型,例如:public class Logger : IFileLogger, IKenticoLogger, IKenticoAndFileLogger, ISmtpLogger 这有点难看。有没有办法给它一个“基础”接口,例如每个接口都基于的ILogger
  • 似乎一长串接口一直在您的软件中,只是以不可互换的 Logger 实例的形式隐藏在设计中。现在它们已经出现在设计中并被认为是“丑陋的”,也许是时候做点什么了。也许重新考虑拥有这么多不同类型的记录器?就个人而言,我认为一长串接口没有任何问题。
  • @MikeHixson - 也许“丑陋”是错误的词。似乎应该可以简单地指定“ILogger”,因为其他接口都派生自它,但我猜不是。

标签: c# .net dependency-injection autofac


【解决方案1】:

您可以在注册类型时尝试使用WithParameter 扩展

//using named parameter
builder.RegisterGeneric(typeof(Logger<>))
    .AsSelf()
    .WithParameter("loggerType", LogType.CMS);

//OR - using typed parameter
builder.RegisterGeneric(typeof(Logger<>))
   .AsSelf()
   .WithParameter(new TypedParameter(typeof(LogType), LogType.CMS));

参考Passing Parameters to Register

【讨论】:

  • 我不确定这是否可行,因为 LogType 可以是任意数量的枚举值,例如,它不会总是 .CMS
  • 是否可以这样做:docs.autofac.org/en/latest/register/… 但改用泛型类型?喜欢BaseRepository ???
【解决方案2】:

我处理您的问题的方式如下:

我按照你的方式注册了 Generic 类。

builder.RegisterGeneric(typeof(Logger<>));

之后我用这样的类型注册它:

 builder.RegisterType<Logger<TProvider>>()
                .As<ILogger<TProvider>>()
                .WithParameter("loggerType", LogType.CMS);

或者你可以像这样使用 Typed 参数:

builder.RegisterType<Logger<TProvider>>()
                    .As<ILogger<TProvider>>()
                    .WithParameter(TypedParameter.From(LogType.CMS)));

将 TProvider 替换为参数,即

builder.RegisterType<Logger<LogProvider>>()
                        .As<ILogger<LogProvider>>()
                        .WithParameter(TypedParamater.From(LogType.CMS)));

【讨论】:

  • 除非我缺少某些东西,否则我不确定这是否可行 - loggerType 可以是任何东西,并不总是LogType.CMS,它可以是许多不同的值并且相同适用于通用TProvider
  • 我头顶上的第一件事是为您使用 ti 注入的每个记录器调用 builder.RegisterType&lt;Logger&lt;LogProvider&gt;&gt;() .As&lt;ILogger&lt;LogProvider&gt;&gt;(); builder.RegisterType&lt;Logger&lt;LogProvider1&gt;&gt;() .As&lt;ILogger&lt;LogProvider1&gt;&gt;(); 。您也可以为每个实例传递相应的LogType
  • 啊,好吧。在页面(网络表单)上看起来如何?例如,对于服务,我有一个公共属性 public IMockService MockService { get; set; } 被注入,鉴于我需要提供构造函数参数,我将如何为记录器执行此操作?
  • 这是一个不同的场景。如果你想注入一个属性,你可以使用属性注入。 Link 到关于属性注入的 autofac 文档。在注册需要属性注入的类型时,您可以使用builder.RegisterType&lt;A&gt;().WithProperty("PropertyName", propertyValue); 按名称注入属性。
  • 或者如果注册类型是reflection component你可以使用builder.RegisterType&lt;A&gt;().PropertiesAutowired();
猜你喜欢
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-25
  • 2012-02-06
  • 1970-01-01
相关资源
最近更新 更多