我有一个抽象调用NLog的记录器。我希望每个logrow都有其调用者来源。一些带有泛型的代码导致奇怪的调用者名称:
ProxyService`1 [MyNameSpace.IController]
在IDE中,当我将鼠标悬停在变量调用者上时,会弹出正确的名称:
{的 MyNameSpace.ProxyService }
如何获得与IDE弹出的值相同的值?
Codesample:
private void SetLogEventInfo(object caller, ILogger logger)
{
string callerOrigin = null;
if (caller != null)
{
callerOrigin = caller.ToString();
}
<code removed>
}
答案 0 :(得分:1)
您可以通过连接:
获得类似于IDE的结果Type type = value.GetType();
return type.Namespace + "." + type.Name;
你会以这种方式获得MyNameSpace.ProxyService`1
。 `1
位指的是泛型类型中的类型参数的数量。没有它,这个名字是暧昧的。如果您坚持要删除它,则可以使用常规的字符串操作(IndexOf
,Remove
)。
答案 1 :(得分:1)
首先,我们的IDE以C#表示法显示您的类名,System.Reflection
与语言无关,因此存在差异。
其次 - 不要依赖ToString()
。仅当未覆盖类型名称时才显示类型名称(因此使用默认的Object
实现)。有多种有效方案要覆盖ToString()
,这会破坏您的代码。
模仿C#代码格式是开箱即用的AFAIK,但有一些技巧可以做到这一点,例如:
var cSharpProvider = CodeDomProvider.CreateProvider("C#");
var variableDecl = new CodeVariableDeclarationStatement(caller.GetType(), "_");
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
cSharpProvider.GenerateCodeFromStatement(variableDecl,
sw,
new CodeGeneratorOptions());
}
sb.Replace("_;", String.Empty);
var callerOrigin = sb.ToString().Trim();
答案 2 :(得分:1)
正在调用对象的ToString
方法,如果不被覆盖,则只返回类型名称,相当于:
public string ToString() {
return this.GetType().ToString();
}
如果您愿意,可以覆盖ToString,但这显然不适用于您无法控制的类型。例如,如果将List<string>
的实例传递给该方法,那么您最终会得到:
System.Collections.Generic.List`1[System.String]
这对你来说可能没什么好处。因此,最好的办法是修改上面的代码来格式化类型:
callerOrigin = FormatObjectForLog(caller);
该方法可能会做的事情(您可以填写空白,因为我不太了解您的要求,以决定如何处理 ProxyService`1 以外的案例:
string FormatObjectForLog(object obj) {
if (obj is IFormattable)
return obj.ToString();
if (obj.GetType().IsGenericType) {
// Get rid of `1 and other crud...
}
...
}
清除反引号的清理类型格式化程序的一个版本如下:
public string FormatType(Type t) {
if (t.IsGenericType) {
return string.Format(
"{0}.{1}<{2}>",
t.Namespace,
t.Name.Substring(0, t.Name.IndexOf('`')),
string.Join(", ", t.GetGenericArguments().Select(FormatType))
);
}
return t.ToString();
}