反射类型到字符串在IDE和代码中有所不同

时间:2014-09-19 09:53:16

标签: c# reflection

我有一个抽象调用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>
        }

3 个答案:

答案 0 :(得分:1)

您可以通过连接:

获得类似于IDE的结果
Type type = value.GetType();
return type.Namespace + "." + type.Name;

你会以这种方式获得MyNameSpace.ProxyService`1`1位指的是泛型类型中的类型参数的数量。没有它,这个名字是暧昧的。如果您坚持要删除它,则可以使用常规的字符串操作(IndexOfRemove)。

答案 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();
}