0

我有一个名为 的类MyClass,它使用两个不同的记录器,名为Logger1Logger2。我使用 log4net 进行日志记录,并希望将 StructureMap 用于 DI。

如果没有 StructureMap,我的课程将如下所示:

public class MyClass
{
    private static readonly ILog Logger1 = LogManager.GetLogger("Logger1"); // Loggers are configured in a config file
    private static readonly ILog Logger2 = LogManager.GetLogger("Logger2");

    public void DoSomething()
    {
        ...
        Logger1.Info("did something");
        ...
        Logger2.Info("need to log this elsewhere");
    }
 }

引入 DI,使用 StructureMap(使用 v3.0.3),我将创建记录器实例成员,并将它们注入构造函数,如下所示: public class MyClass { private readonly ILog Logger1; 私有只读 ILog Logger2;

    myClass(ILog logger1, ILog logger2)
    {
        this.Logger1 = logger1;
        this.Logger2 = logger2;
    }

    public void DoSomething()
    {
        ...
        Logger1.Info("did something");
        ...
        Logger2.Info("need to log this elsewhere");
    }
 }

问题是,我无法让 StructureMap 为我正确地连接它。我尝试像这样连接记录器:

For<ILog>.Use(()=> LogManager.GetLogger("Logger1")).Named("Logger1");
For<ILog>.Use(()=> LogManager.GetLogger("Logger2")).Named("Logger2");

这样做会让我清空(未配置的)记录器)。由于没有为 ILog 注册默认实例,替换Use()为我的异常。Add()

有人知道我该怎么做吗?

4

3 回答 3

4

如果记录器执行不同的角色,那么我将创建两个从 ILog 继承的接口来反映这一点。这样你就可以毫无问题地配置 StructureMap 来处理它们。

于 2014-06-26T11:29:09.027 回答
0

我最终做了以下事情:我按照 Rob 的建议创建了两个接口:ILogger1ILogger2. 由于两者具有相同的 API,因为我需要它们提供相同类型的功能,所以它们都继承自相同的接口 - 尽管不是 log4net.ILog按照 Steven 的建议:

interface IMyLog
{
    void Info(object message);
    void Info(string format, params object[] args);
}

interface ILogger1 : IMyLog { }
interface ILogger2 : IMyLog { }

此外,由于此 API 的实现与我的需求相同,因此我有一个具体的类MyLogger,同时实现ILogger1ILogger2。如果我需要不同的实现,那么我很容易拥有显式接口实现或单独的类。仅My Logger依赖于 log4net,因为它使用它来实现:

enum LoggerType { Logger1, Logger2 }

internal class MyLogger : ILogger1, ILogger2
{
    private readonly ILog _log;

    public MyLogger(LoggerType loggerName)
    {
        switch (loggerName)
        {
            case LoggerType.Logger1:
                _log = LogManager.GetLogger("first-log");
                break;
            case LoggerType.Logger2:
                _log = LogManager.GetLogger("second-log");
                break;
            default:
                throw new ArgumentException("Invalid logger name", "loggerName");
        }
    }

    public void Info(object message)
    {
        _log.Info(message);
    }

    public void Info(string format, params object[] args)
    {
        _log.InfoFormat(format, args);
    }
} 

为了向StructureMap注册它,我在注册表中使用了以下代码:

For<ILogger1>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger1).Singleton();   // I want only one logger per type
For<ILogger2>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger2).Singleton();

这一切都非常有效。所以,感谢 Steven 和 Rob 的建议。我真的学到了一些东西。我希望我能不止一次地投票赞成一个答案和一个回应。

所以,总结一下,我:

  • 为每种记录器创建了一个单独的界面(即使现在说它听起来很直观)。
  • 为记录器接口创建了一个基本接口,因为根据我的需要,它们具有相同的 API (YMMV)
  • 创建了一个实现这两个接口的具体记录器适配器,因为它适合我的需要(再次是 YMMV)
  • 分享接口API的实现,原因就在上面
  • 注册每个接口以创建具有在构造函数中传递的不同类型的具体记录器
  • 使用工厂方法使用 log4net 配置具体记录器以确定要使用的记录器
于 2014-06-27T13:25:51.233 回答
0

作为上述答案的替代方案,这可以专门在 StructureMap 中解决(我相信适用于问题中使用的 SM 版本)。您可以通过在注册表中包含以下内容来准确地告诉 StructureMap 如何构建MyClass

For<MyClass>().Use(x => new MyClass(x.GetInstance<ILog>("Logger1"), x.GetInstance<ILog>("Logger2")));
于 2017-07-25T14:44:21.740 回答