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属性的类的方法的调用,并从拦截器中注入它。