C# 在基类中定义的log4net记录器

C# 在基类中定义的log4net记录器,c#,inheritance,logging,static,log4net,C#,Inheritance,Logging,Static,Log4net,我想在MVC控制器抽象基类中构建log4net记录器,如下所示: protected static readonly ILog Log = LogManager.GetLogger(typeof(AuthorizedController)); 通过这种方式,我可以定义一次记录器并完成它。唯一的问题是日志输出中的logger属性始终是AuthorizedController,如果我从AuthorizedController继承了FooController,我希望日志输出反映出这一点 做这件事的好

我想在MVC控制器抽象基类中构建log4net记录器,如下所示:

protected static readonly ILog Log = LogManager.GetLogger(typeof(AuthorizedController));
通过这种方式,我可以定义一次记录器并完成它。唯一的问题是日志输出中的logger属性始终是
AuthorizedController
,如果我从
AuthorizedController
继承了
FooController
,我希望日志输出反映出这一点


做这件事的好方法是什么?

我不确定调用
LogManager.GetLogger()
的代价有多高,但我怀疑log4net系统中存在一些聪明的缓存和/或延迟初始化,可以让请求的实例可供快速检索。毕竟,没有理由用同一类型参数调用
LogManager.GetLogger()
两次会返回不同的实例

也就是说,也许用以下属性替换字段就足够了

protected ILog Logger
{
    get { return LogManager.GetLogger(GetType()); }
}

GetType()
是虚拟的且重载的,因此在调用此属性时,每个具体类型都将提供其类型。

我使用IoC容器做了类似的事情,但我想您可以掌握使用自己的容器的想法。 基本上,我在请求类型构造函数中注入了ILog,但没有绑定到实例

kernel.Bind().ToProvider();
创建公共对象(IContext上下文)
{
返回LogManager.GetLogger(context.Request.Target.Member.DeclaringType);
}
因此,每种类型都会收到一个与在构造函数中执行
GetLogger(GetType())
相同的记录器。

使用静态记录器(或通常的静态实例)是一种不好的做法。这很容易导致不相关组件之间出现不必要的耦合

你应该考虑向游戏添加一个依赖性注入/控制框架的逆。将记录器注入类的ctor。大多数框架允许您在不同的上下文中定义不同的实现

我们在产品中使用

您还可以查看以找到一个将日志记录与DI一起使用的示例,正如Steve Guidi所建议的那样-使用GetType为类型的特定实例创建日志记录程序。您可以保存对logger实例的引用,该实例将在备份字段中调用LogManager.GetLogger:

    private ILog _log;
    protected ILog Log => _log ?? (_log = LogManager.GetLogger(GetType()));

游戏中是否有IoC库?
检索名为name参数的记录器。如果命名的记录器已存在,则将返回现有实例。否则,将创建一个新实例。
是的,我认为我太沉迷于静态实例,而它实际上并不需要是静态的。Log4net从哈希表读取数据来解析记录器。O(1)还不错,但我不喜欢每次需要访问记录器时都进行多个方法调用。也许最好的办法是让每个派生类在其构造函数中调用此属性,并保存记录器本身的副本?除了代码中的样板文件比较混乱之外,还有什么功能上的区别吗?表明这是预期用途。很公平,这是一个意见问题。拥有静态实例是访问全局上下文的快速解决方案。问题是,它将类与外部服务的实现结合起来。通过推动而不是拉动服务,您可以创建更好的解耦。另外,使用这种方法编写测试在编写测试时效果更好。我还需要进一步研究,但现在史蒂夫的答案就足够了。
    private ILog _log;
    protected ILog Log => _log ?? (_log = LogManager.GetLogger(GetType()));