如何将依赖项名称作为构造函数参数注入
本文关键字:构造函数 参数 注入 依赖 | 更新日期: 2023-09-27 17:55:50
使用 Autofac,我可以使用以下代码注册一个类以使用属性注入解析接口:
builder.RegisterType<Log4NetAdapter>()
.As<ILogger>()
.PropertiesAutowired()
.InstancePerDependency();
但是,我的Log4NetAdapter
类有一个构造函数参数,该参数需要调用类的名称。这样,我就可以根据调用类的名称记录事件。
public class Log4NetAdapter : ILogger
{
private readonly ILog _logger;
public Log4NetAdapter(string logName)
{
_logger = LogManager.GetLogger(logName);
}
...
}
如何注入名称(即 typeof(dependency).Name
)的依赖关系到属性注入类的构造函数中,因为每个依赖都有自己的Log4NetAdapter
实例?
更新:基于LogInjectionModule示例以及Autofac如何进行属性注入,我扩展了该模块以执行构造函数和属性注入。
注意:我已经修复了传递给LogManager
的类型,OnComponentPreparing
使用声明类型。这使得例如 Resolve<Func<Service>>
使用正确的日志类型。
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<object> 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<LogInjectionModule>();
cb.RegisterType<Service>();
var c = cb.Build();
var service = c.Resolve<Service>();
你只使用logName
来有效地通过命名解析ILog
,那么为什么不直接注入一个ILog
呢?
public class Log4NetAdapter : ILogger
{
private readonly ILog _logger;
public Log4NetAdapter(ILog logger)
{
_logger = logger;
}
...
}
好的,所以现在我只是稍微移动了问题,但我也减少了与其他类(即 LogManager
的耦合。
因此,如果我使用 unity,我会这样做以确保我得到正确的记录器:
var childContainer = container.CreateChildContainer();
childContainer.RegisterInstance<ILog>(LogManager.GetLogger(logName));
var adaptor = childContainer.Resolve<Log4NetAdapter>();
子容器阻止任何其他代码访问该ILog
。你可以随心所欲地做到这一点,我对你的代码一无所知。