我有一个通用类:
public class GenericClass<A>
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public void Blah(A a)
{
Logger.Info("Test log");
}
}
与简单的NLog配置一起使用:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="console" xsi:type="ColoredConsole" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="console" />
</rules>
</nlog>
我希望我的日志输出看起来像:
...|INFO|NLogTests.GenericClass<System.String>|Test log
相反,我看到的是:
...|INFO|NLogTests.GenericClass`1|Test log
如何让记录器使用完全限定的类型名称而不是仅显示通用参数数量的基本名称?
答案 0 :(得分:3)
您可以使用:
代替GetCurrentClassLoggerLogger log = LogManager.GetLogger(GenericToString(typeof(GenericClass<A>)));
…
string GenericToString(Type type) {
var typeName = type.Namespace + "." + type.Name;
var args = type.GetGenericArguments();
if (args.Count() == 0) return typeName;
typeName = typeName.Remove(typeName.LastIndexOf("`"));
return typeName
+ "<"
+ string.Join(", ", args.Select(a=>GenericToString(a)))
+ ">";
}
将GenericToString
放置在随机实用函数/扩展方法的任何位置。
免责声明:此功能现已被黑客攻击,可能无法正常工作,导致计算机着火,或导致秃顶。
答案 1 :(得分:1)
如果你正在使用C#6&amp; .NET&gt; 4.5,然后你可以做一个巧妙的技巧来使用CSharpCodeProvider
:
public static class LogManager<T>
{
public static Logger GetLogger()
{
return LogManager.GetLogger(typeof(T).GetFriendlyName());
}
}
public static class TypeExtensions
{
public static string GetFriendlyName(this Type t)
{
using (var provider = new CSharpCodeProvider())
{
var typeRef = new CodeTypeReference(t);
return provider.GetTypeOutput(typeRef);
}
}
}
然后你可以像这样使用这个扩展名:
var logger = LogManager<Dictionary<string, int>>.GetLogger();
logger.Info("logger name contains generic params");
输出将是:
2016-09-23 13:52:14.6342|INFO|System.Collections.Generic.Dictionary<string, int>|logger name contains generic params