如何将依赖项名称作为构造函数参数注入

使用Autofac,我可以使用以下代码注册一个类来解析使用属性注入的接口:

builder.RegisterType() .As() .PropertiesAutowired() .InstancePerDependency(); 

但是,我的Log4NetAdapter类有一个构造函数参数,需要调用类的名称。 这样,我可以根据调用类的名称记录事件。

 public class Log4NetAdapter : ILogger { private readonly ILog _logger; public Log4NetAdapter(string logName) { _logger = LogManager.GetLogger(logName); } ... } 

如果每个依赖项都有自己的Log4NetAdapter实例,我怎样才能将typeof(dependency).Name的名称(即typeof(dependency).Name )注入到属性注入类的构造函数中?

更新:基于LogInjectionModule示例以及Autofac如何进行属性注入 ,我已经扩展了模块以执行构造函数和属性注入。

注意:我已修复传递给LogManagerLogManager的类型以使用声明类型。 这使得例如Resolve>使用正确的日志类型。

  using System.Linq; using log4net; public class LogInjectionModule : Module { protected override void AttachToComponentRegistration(IComponentRegistry registry, IComponentRegistration registration) { registration.Preparing += OnComponentPreparing; registration.Activating += OnComponentActivating; } private static void OnComponentActivating(object sender, ActivatingEventArgs e) { InjectLogProperties(e.Context, e.Instance, false); } private static void OnComponentPreparing(object sender, PreparingEventArgs e) { e.Parameters = e.Parameters.Union(new[] { new ResolvedParameter( (p, i) => p.ParameterType == typeof(ILog), (p, i) => LogManager.GetLogger(p.Member.DeclaringType)) }); } private static void InjectLogProperties(IComponentContext context, object instance, bool overrideSetValues) { if (context == null) throw new ArgumentNullException("context"); if (instance == null) throw new ArgumentNullException("instance"); var instanceType = instance.GetType(); var properties = instanceType .GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(pi => pi.CanWrite && pi.PropertyType == typeof(ILog)); foreach (var property in properties) { if (property.GetIndexParameters().Length != 0) continue; var accessors = property.GetAccessors(false); if (accessors.Length == 1 && accessors[0].ReturnType != typeof(void)) continue; if (!overrideSetValues && accessors.Length == 2 && (property.GetValue(instance, null) != null)) continue; ILog propertyValue = LogManager.GetLogger(instanceType); property.SetValue(instance, propertyValue, null); } } } 

关于如何使用该模块,这是一个示例:

 public class Service { public Service(ILog log) { ... } } var cb = new ContainerBuilder(); cb.RegisterModule(); cb.RegisterType(); var c = cb.Build(); var service = c.Resolve(); 

你只使用logName来有效地解析名称ILog ,那么为什么不注入一个ILog呢?

 public class Log4NetAdapter : ILogger { private readonly ILog _logger; public Log4NetAdapter(ILog logger) { _logger = logger; } ... } 

好的,所以现在我刚刚解决了这个问题,但是我也把它与其他类(即LogManager耦合程度降低了。

因此,如果我使用统一,我会这样做,以确保我得到正确的记录器:

 var childContainer = container.CreateChildContainer(); childContainer.RegisterInstance(LogManager.GetLogger(logName)); var adaptor = childContainer.Resolve(); 

子容器阻止任何其他代码访问该ILog 。 你可以随心所欲地做到这一点,我对你的代码不再了解。