我正在写一个应用程序。我使用NLog进行日志记录。在这个应用程序中几乎每个对象都可以写入日志。我为此定义了受保护的成员:
protected Logger logger;
protected virtual Logger Logger
{
get { return logger ?? (logger = LogManager.GetLogger(this.GetType().ToString())); }
}
在这种情况下,我需要为应用程序中的每个基类复制/粘贴此代码。或者我看到其他选项:使用logger定义特定于应用程序的根对象并将其子类化。但从语义上讲,这听起来是错误的,因为对我来说这不是真正的“是 - ”的情况。
还有更好的选择吗?
答案 0 :(得分:7)
有时我真的希望C#支持多重继承或mixins ....
你可以写一个扩展方法:
public static Logger Logger(this object obj) {
return LogManager.GetLogger(obj.GetType());
}
缺点是它会慢一点,因为创建的实例没有被缓存(NLog内部除外,这是一个实现细节),但你可以自己做:
public static Logger Logger(this object obj) {
Logger logger;
Type type = obj.GetType();
// s_loggers is static Dictionary<Type, Logger>
if (!s_loggers.TryGetValue(type, out logger)) { // not in cache
logger = LogManager.GetLogger(type);
s_loggers[type] = logger; // cache it
}
return logger;
}
你可以这样称呼它:
this.Logger.Log(...)
明显的缺点是任何对象都可以写入任何其他对象的记录器。
关于内存泄漏的评论(现已删除):
第一个实现解决了这个问题。但是,它不是任何静态物体的泄漏。如果您无法访问这些对象,那将是一个泄漏。作为替代方案,您可以将WeakReference
缓存到记录器而不是记录器本身,但我认为没有意义,因为我相信NLog本身已经存在一些缓存。否则,NLog总是必须为每种类型创建一个新的记录器实例。
答案 1 :(得分:2)
我建议您使用静态记录器,以便获得每类记录器。这样可以停止为每个实例创建记录器的开销(记录器是线程安全的):
class MyClass
{
static readonly Logger logger = LogManager.GetCurrentClassLogger();
}
GetCurrentClassLogger将使您不必显式地命名记录器,但缺点是额外的开销,因为它必须在运行时从堆栈跟踪中找出记录器的名称。
在大多数情况下,这可能不是什么大问题,但除此之外,这样做要快一点:
class MyClass
{
static readonly Logger logger = LogManager.GetLogger("MyClass");
}
我会坚持使用GetCurrentClassLogger,直到/除非轻微的开销在您的解决方案中成为问题。
我得到的印象是你正试图减少打字,和/或你正在解决复制和粘贴重复代码的(好)自然厌恶。
然而,这种使用静态初始化程序每个类具有记录器的模式被广泛接受,并且在大多数情况下效果最佳。你可能最好坚持使用它,也许设置一个代码片段来为你节省一些打字。
如果您对此仍然不满意,依赖注入(通过构造函数或属性注入)甚至面向方面的日志记录管理可能是您需要调查的其他内容。