关于c#:默认依赖注入?

Default dependency injection?

本问题已经有最佳答案,请猛点这里访问。

我需要在我的域中记录很多东西,因此我的大部分域和应用程序服务都依赖于日志记录实现。假设我创建了这个小合同:

1
2
3
4
5
public interface ILogger {

    void Info(string message);

}

伟大的。现在我实现了一个基于log4net的基础设施服务:

1
2
3
4
5
6
7
8
public class Log4NetProxy : ILogger {

    private ILog _logger = LogManager.GetLogger();

    public void Info(string message) {
        _logger.Info(message);
    }
}

但是,由于我的大多数类都有其他依赖项,而不仅仅是一个日志记录器,因此我越来越接近于一个构造函数过度注入模式。

1
2
3
4
5
6
7
public class MyService : IMyService {

    public MyService(ILogger logger, IRepository repo, IAlsoNeedSettings settings) {

    }

}

如何避免注入诸如设置或日志记录之类的基本核心需求,并只关注我真正需要的依赖性?属性注入?服务立面?静态日志工厂?


[关于拦截器的rant+代码被删除,因为这不是您需要的:)]

我发现属性注入通常是可行的,因为它避免了通常不太有趣的样板代码。

... and i assign the umpteenth ISomething from the constructor value to
the property ...

我不知道如何在自动空调中使用它(我主要使用castle.windsor),但我建议它是一种低维护和避免建造商膨胀的好方法。

编辑:显然,MarkSeemann提到的问题提到拦截是处理这些案例的有效方法,所以我会把原来的rant+代码放回去。我不确定它是否与他所指的相符,但它可能会给你一些想法。

我真的很喜欢Castle Windsor拦截系统,它有点像面向方面的编程,在这里您可以将解析的组件封装在拦截器中,然后根据参数、方法名等决定如何操作。

下面是我的拦截记录器示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class LoggingInterceptor: IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        using (Tracer t = new Tracer(string.Format("{0}.{1}", invocation.TargetType.Name, invocation.Method.Name)))
        {
            StringBuilder sb = new StringBuilder(100);
            sb.AppendFormat("IN (", invocation.TargetType.Name, invocation.Method.Name);
            sb.Append(string.Join(",", invocation.Arguments.Select(a => a == null ?"null" : DumpObject(a)).ToArray()));
            sb.Append(")");
            t.Verbose(sb.ToString());

            invocation.Proceed();

            sb = new StringBuilder(100);
            sb.AppendFormat("OUT {0}", invocation.ReturnValue != null ? DumpObject(invocation.ReturnValue) :"void");
            t.Verbose(sb.ToString());
        }
    }

    private string DumpObject(object argument)
    {
        // serialize object
    }
}

然后在安装期间注册此记录器侦听器,并将其应用于WCF服务中的感兴趣的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// register interceptors
_container.Register(
    Classes.FromAssemblyInThisApplication()
    .BasedOn<IInterceptor>()
    .WithServiceBase()
    .Configure(c => c.Named(c.Implementation.Name))
);

// apply them
_container.Register
(
    Component.For<IService>()
        .ImplementedBy<ServicesImplementation.Service>()
        .Named("Service")
        .LifestylePerWcfOperation()
        .Interceptors("LoggingInterceptor")
);

您可以考虑拦截对需要ilogger或具有ilogger属性的类的方法的调用,并从拦截器中注入它。