所以我对此做了很多研究,但没有找到任何答案,我说“是的,那个”。我希望博学多才的 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
。
正如我所看到的,我有几个选择。
- 将其注入到构造函数中的 MyClass 中。
- 使用全球可用的服务定位器检索它。
- 使用方法装饰器和 AOP 为我完成日志记录。
这些似乎都不是很好的选择。#3 看起来是不可能的,因为我在我的业务逻辑中间记录,而不仅仅是简单地跟踪我的方法调用、输入参数和/或抛出的异常。#2,虽然看起来很简单,但单元测试真的很难。当然,我想对所有内容进行单元测试。#1,虽然它可以正常工作,但我所有的业务逻辑都被与业务对象本身无关的日志对象弄乱了。
任何替代想法或对上述选项之一的想法?非常感谢!
编辑:为了清楚起见,我已经知道如何进行 DI(我使用 Unity),并且我已经知道一个好的日志框架(我使用 log4net)。只是想知道如何以最智能的方式在整个应用程序中使用架构意义上的日志记录。
* 编辑 *
I marked Mark Seeman's answer as the solution. I went through my application and found that most of my logging calls were doing the same thing a decorator could do. Namely, log the entry to the method, any exceptions thrown, and exit return values.
Some cases I still needed to log directly inside a method. An example would be where I want to fail fast in a method which doesn't return anything but not throw an Exception. In those cases I have a singleton which holds a reference a LogProvider
which will in turn retrieve a named log instance. The code looks similar to this:
private ILog logger = LogProviderFactory.Instance.GetLogger(typeof(Foo));
LogProviderFactory has a method SetProvider
which allows you to swap out the singleton. So in unit testing I can do:
// LogProviderFactory.Instance now is our mock
LogProviderFactory.SetProvider(MockLogProvider);
The logging decorator uses the same LogProvider as the singleton (which it obtains through injection), so logging is unified throughout the system.
So really the end solution was mostly option #3, and a hybrid #2 (where it's the service locator pattern but the service is 'injected' into the locator).
AOP
As far as "aspect oriented programming" goes, I was a bit disappointed in the limitations of the language. Hoping AOP will be treated as a first-class citizen in future releases.
- I tried PostSharp but couldn't get it running on my machine correctly. Additionally it was a big restriction that you had to have PostSharp installed on your system to use it (as opposed to just calling a dll which comes with the solution or something similar).
- I used LinFu and was able to get it partially working. It blew up in a few instances however. The new 2.0 release is barely documented, so that was a hurdle.
- Interface interception with Unity however seems to work well out of the box. I got lucky that most things I wanted to log were in classes implementing interfaces.