我对此进行了大量的研究,但没有找到我需要的答案。我希望 StackOverflow 的聪明人能够帮助我。
我在不同的情况下遇到了这个问题。比如我有一个 C# 应用程序,我想记录重要的事情。
public class MyClass
{
...
public void ImportantMethod()
{
DoInterestingThing();
var result = SomethingElseImportant();
if (result == null)
{
logger.Log("I wasn't expecting that. No biggie.");
return;
}
MoreInterestingStuff();
}
我感兴趣的是,我应该从哪里获取
logger
。我有几个选择:
1. 在构造函数中将其注入到MyClass中。 2. 使用全局可用的服务定位器检索它。 3. 使用方法装饰器和AOP让日志记录自动完成。
这些选项都不是很好。#3似乎不可能,因为我正在记录我的业务逻辑,而不仅仅是跟踪我的方法调用、输入参数和/或抛出的异常。#2虽然简单,但似乎很难进行单元测试。当然,我希望对所有内容进行单元测试。#1虽然可以正常工作,但会在我的业务逻辑中添加日志对象,与业务对象本身无关。
还有其他想法,或者对上述选项有什么看法吗?非常感谢!
编辑:为了明确起见,我已经知道如何进行DI(我使用Unity),并且我已经知道一个好的日志记录框架(我使用log4net)。只是想知道如何在整个应用程序中以最智能的方式使用日志记录。
* 编辑 *
我将Mark Seeman的答案标记为解决方案。我检查了我的应用程序,发现大多数日志记录调用都可以使用装饰器完成相同的工作。即记录方法的输入、抛出的任何异常和退出返回值。
有些情况下我仍然需要直接在方法内部记录日志。一个例子是我想在不返回任何内容但不抛出异常的方法中快速失败。在这些情况下,我有一个单例,它持有一个LogProvider
的引用,后者将检索一个命名的日志实例。代码看起来类似于这样:
private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));
LogProviderFactory有一个名为SetProvider
的方法,允许您替换单例。因此,在单元测试中,我可以执行以下操作:
// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);
日志装饰器使用与单例相同的LogProvider(通过注入获得),因此整个系统中的日志记录是统一的。
所以最终解决方案主要是选项#3,以及混合使用选项#2(它是服务定位器模式,但服务被“注入”到定位器中)。
AOP
就“面向方面编程”而言,我对语言的限制感到有些失望。希望在未来的版本中AOP将被视为一级公民。
- 我尝试过PostSharp,但无法在我的计算机上正确运行它。此外,一个很大的限制是你必须在系统上安装PostSharp才能使用它(而不是只调用随解决方案一起提供的dll或类似的东西)。
- 我使用了LinFu,并且能够部分地使其工作。然而,在某些情况下它会崩溃。新的2.0版本几乎没有文档,这是一个障碍。
- 然而,使用Unity进行接口拦截似乎可以直接开箱即用。我很幸运,因为我想要记录的大多数内容都在实现接口的类中。