C# Log4Net使用泛型类和精度参数的转换模式不正确

C# Log4Net使用泛型类和精度参数的转换模式不正确,c#,log4net,C#,Log4net,C#logging framework log4net在转换模式中使用精确参数(例如,%logger{1})时,似乎无法正确处理所有记录器和附加器的通用类名。因为我根本找不到任何相关的问题,所以我决定发布一个详细的问题摘要,希望有人知道解决方法 例如,具有上述对话模式的泛型类DiskSaviourHook应该生成DiskSaviourHook,但却输出0,Culture=neutral,PublicKeyToken=null](这显然是错误的)。经过进一步调查,我发现这是因为log4net解析器

C#logging framework log4net在转换模式中使用精确参数(例如,
%logger{1}
)时,似乎无法正确处理所有记录器和附加器的通用类名。因为我根本找不到任何相关的问题,所以我决定发布一个详细的问题摘要,希望有人知道解决方法

例如,具有上述对话模式的泛型类
DiskSaviourHook
应该生成
DiskSaviourHook
,但却输出
0,Culture=neutral,PublicKeyToken=null]
(这显然是错误的)。经过进一步调查,我发现这是因为log4net解析器在与
{1}
精度参数一起使用时只查找最后一个点


更具体地说,记录器名称
Sigma.Core.Training.Hooks.Saviors.DiskSaviorHook'1[[Sigma.Core.Architecture.INetwork,Sigma.Core,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null]
与任何其他记录器名称一样处理,尽管它是通用的,并且比通常有更多的点(版本的最后一个点的处理方式与实际类的最后一个点相同)。这个问题是否有任何已知的修复/解决方法?

转换模式工作正常。在log4net中,记录器名称是分层的,并且分层的级别由句点分隔。这恰好与名称空间中类的命名方式相一致,因此将类名用于记录器名称是一种普遍的做法(从而使为整个名称空间配置日志记录变得容易)。由于分布广泛,log4net为其提供了重载:
LogManager.GetLogger(Type)
实现为
LogManager.GetLogger(Assembly.GetCallingAssembly(),Type.FullName)

不幸的是,这对泛型不起作用。泛型类型有一个包含其类型参数的
FullName
,这打破了log4net使用的层次结构。您仍然可以有一个名为
Sigma.Core.Training.Hooks.Saviors.DiskSaviorHook'1的记录器[[Sigma.Core.Architecture.INetwork,Sigma.Core,Version=1.0.0,Culture=neutral,PublicKeyToken=null]
,当然,但就log4net而言,它有一个特别丑陋的层次结构,包括
DiskSaviorHook'1之类的组件[[Sigma
。层次结构纯粹是语法上的,而不是基于对实际类名的解析。事实上,为记录器使用类名只是一种惯例,尽管这是一种有用的惯例

如果我是一名log4net开发人员,并且不关心向后兼容性,我会将
LogManager.GetLogger(Type)
实现为
LogManager.GetLogger(Assembly.GetCallingAssembly(),Type.Namespace+Type.Name)
,这不会遇到这个问题。但是我不是,而且我也懒得打开一个问题

对于客户端代码,有一个简单的解决方法。替换如下代码:

static ILog log = LogManager.GetLogger(typeof(DiskSaviourHook<T>));

后者在文档中被称为一个样板文件,用于获取类名而不提及它,它也可以为泛型做“正确的事情”(我仍然更喜欢自己简单地输入类名而不是反射。)

为什么要给记录器这样一个笨拙的名称?这是一个长期存在的误解(没有文档的帮助)您必须为记录器使用类名。正如您所发现的,这在泛型的情况下效果尤其糟糕。我要说的问题不是精度参数在某种程度上出现了故障(不是这样),而是类名没有去掉它的类型参数签名(包括汇编).GetLogger.GetLogger(Type)实现为
LogManager.GetLogger.GetLogger(Assembly.GetCallingAssembly(),Type.FullName)
。对于泛型来说,这可能是个坏主意。我会将其设置为
LogManager.GetLogger(Assembly.GetCallingAssembly()),type.Namespace+type.Name)
,它省略了扩展泛型的类型参数。显然,客户机代码也可以这样做,尽管它很笨拙。@Jeroenmoster非常感谢,我确实没有意识到这一点。我现在已经让所有日志记录者都使用这个“修复的”名字,很好。他们真的应该在某个地方提到……不管怎样,你想把它作为一个答案(分数)吗?也可以,还有一个更简单的解决方法。如果您真的想要通用名称(包括参数)作为记录器名称,并且想要在布局中获取类名,那么这将非常困难;您可能需要一个自定义属性,甚至自定义布局。我想大多数人都会对没有但是,关于上一个版本(
GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType
)-该版本不适用于泛型。这是我在您提到
GetLogger(Assembly.GetCallingAssembly(),Type.Namespace+Type.Name)之前最初使用的版本
version,您确定它应该工作吗?它与使用
GetLogger(Type)
遇到的问题相同,因为它是同一个函数。@1337:我的断言基于以下事实:
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName
返回没有扩展参数的类名。使用log4net 1.2.13进行测试时,这样做会形成一个泛型类,实际上会将
%logger{1}
记录为
泛型类`1
,而不包含参数。如果您的体验不同,则需要更多详细信息。
static ILog log = LogManager.GetLogger(typeof(DiskSaviourHook<>));
static ILog log = LogManager.GetLogger(
    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType
);