简单的Injector设置属性,同时构建对象图

时间:2012-06-22 02:42:53

标签: c# .net design-patterns dependency-injection simple-injector

使用Simple Injector我在记录器中遇到了一个共同的主题,我在记录器注入的服务对象的构造函数中设置了记录器名称。当服务写入日志时,可以通过此日志名轻松识别它。

由于将为每项服务设置LogNames,因此每个对象图形请求的记录器应该是唯一的。

我想在构建图表时自动执行此操作,我已经在ExpressionBuilt()中进行了调查但是我正在努力并且尚未得到我想要工作的东西 - 这是否可能(或者是可以的)想做什么??

我的构造函数代码如下(这个LogName属性设置代码在我的大多数服务中都很常见。)

谢谢,

克里斯

public interface ILogger
{
    void LogMessage(string message, LogLevel level,
        ILoggableCompany company = null);

    string LogName {get; set; }
}

public BusinessUnitService
{
    private readonly IUnitOfWork unitOfWork;
    private readonly ILogger logger;

    public BusinessUnitService(IUnitOfWork unitOfWork, 
        ILogger logger)
    {
        this.unitOfWork = unitOfWork;
        this.logger = logger;

        // it would be great if we could take away this 
        // line and set it automatically
        this.logger.LogName = this.GetType().ToString();
    }
}

1 个答案:

答案 0 :(得分:1)

此设计看起来有点像log4net的Logger<T>设计,其中T将是为其创建记录器的类。虽然我无法调查你的设计,但我想知道:aren't you logging too much?

如果您确实需要这样做,请至少从LogName界面删除ILogger属性,因为它在那里没有业务。这意味着您必须从构造函数中删除设置此属性的代码,这绝对没问题,因为这是整个地方的代码重复。

您要做的是基于上下文的注入,这不是开箱即用的,但Simple Injector wiki包含一个Context Bases Injection section,解释了如何添加此支持。此文档页面甚至使用Logger<T>作为示例: - )

使用wiki所指的the extension method,您可以执行以下操作:

public interface ILogger
{
    void LogMessage(string message, LogLevel level,
        ILoggableCompany company = null);

    // No LogName property here. Keep it clean.
}

public class LoggerImpl : ILogger
{
    public void LogMessage(string message, 
        LogLevel level, ILoggableCompany company)
    {
       // implementation
    }

    // Property only part of the implementation.
    public string LogName {get; set; }
}

// The parent contains information about the type in 
// which ILogger is injected.
container.RegisterWithContext<ILogger>(parent =>
{
    // Retrieve a new LoggerImpl instance from the container 
    // to allow this type to be auto-wired.
    var logger = container.GetInstance<LoggerImpl>();

    // ImplementationType is null when ILogger is
    // requested directly (using GetInstance<ILogger>())
    // since it will have no parent in that case.
    if (parent.ImplementationType != null)
    {
        // Set the LogName with the name of the class 
        // it is injected into.
        logger.LogName = parent.ImplementationType.Name;
    }

    return logger;
});

// Register the LoggerImpl as transient. This line is
// in fact redundant in Simple Injector, but it is important
// to not accidentally register this type with another
// lifestyle, since the previous registration depends on it
// to be transient.
container.Register<LoggerImpl>();

因为这可以通过挂钩到BuiltExpression事件,并通过重新连接表达式来解决实例,所以这几乎与使用Func<T>工厂方法的注册一样快。