如何使用反射获得泛型类型的正确文本定义?

时间:2008-12-30 22:13:43

标签: c# generics reflection

我正致力于代码生成,并遇到了泛型问题。这是导致我问题的“简化”版本。

Dictionary<string, DateTime> dictionary = new Dictionary<string, DateTime>();
string text = dictionary.GetType().FullName;

使用上面的代码段,text的值如下:

 System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, 
 Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.DateTime, mscorlib, 
 Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

(添加换行符以提高可读性。)

有没有办法在不解析上面的字符串的情况下以不同的格式获取类型名称(type)?我希望text得到以下结果:

System.Collections.Generic.Dictionary<System.String, System.DateTime>

6 个答案:

答案 0 :(得分:28)

没有内置方法可以在.Net Framework中获得此表示形式。也就是因为没有办法让它变得正确。在C#样式语法中有许多不能表示的构造。例如,“&lt;&gt; foo”是IL中的有效类型名称,但不能用C#表示。

但是,如果您正在寻找一个非常好的解决方案,它可以很快地手工实施。以下解决方案适用于大多数情况。它不会处理

  1. 嵌套类型
  2. 非法C#名称
  3. 其他几个场景
  4. 示例:

    public static string GetFriendlyTypeName(Type type) {
        if (type.IsGenericParameter)
        {
            return type.Name;
        }
    
        if (!type.IsGenericType)
        {
            return type.FullName;
        }
    
        var builder = new System.Text.StringBuilder();
        var name = type.Name;
        var index = name.IndexOf("`");
        builder.AppendFormat("{0}.{1}", type.Namespace, name.Substring(0, index));
        builder.Append('<');
        var first = true;
        foreach (var arg in type.GetGenericArguments())
        {
            if (!first)
            {
                builder.Append(',');
            }
            builder.Append(GetFriendlyTypeName(arg));
            first = false;
        }
        builder.Append('>');
        return builder.ToString();
    }
    

答案 1 :(得分:20)

由于@LukeH's comment,一个好的,干净的选择是

using System;
using System.CodeDom;
using System.Collections.Generic;
using Microsoft.CSharp;
//...
private string GetFriendlyTypeName(Type type)
{
    using (var p = new CSharpCodeProvider())
    {
        var r = new CodeTypeReference(type);
        return p.GetTypeOutput(r);
    }
}

答案 2 :(得分:4)

今晚我用扩展方法玩弄了一些东西,我试图找到你问题的答案。结果如下:这是一个无保修代码。 ; - )

internal static class TypeHelper
{
    private const char genericSpecialChar = '`';
    private const string genericSeparator = ", ";

    public static string GetCleanName(this Type t)
    {
        string name = t.Name;
        if (t.IsGenericType)
        {
            name = name.Remove(name.IndexOf(genericSpecialChar));
        }
        return name;
    }

    public static string GetCodeDefinition(this Type t)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendFormat("{0}.{1}", t.Namespace, t.GetCleanName());
        if (t.IsGenericType)
        {
            var names = from ga in t.GetGenericArguments()
                        select GetCodeDefinition(ga);
            sb.Append("<");
            sb.Append(string.Join(genericSeparator, names.ToArray()));
            sb.Append(">");
        }
        return sb.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        object[] testCases = { 
                                new Dictionary<string, DateTime>(),
                                new List<int>(),
                                new List<List<int>>(),
                                0
                            };
        Type t = testCases[0].GetType();
        string text = t.GetCodeDefinition();
        Console.WriteLine(text);
    }
}

答案 3 :(得分:2)

string text = dictionary.ToString();

提供了几乎所要求的内容:

System.Collections.Generic.Dictionary`2[System.String,System.DateTime]

答案 4 :(得分:0)

我认为.NET没有任何内置可以做到这一点,所以你必须自己做。我认为反射类提供了足够的信息来重建这种形式的类型名称。

答案 5 :(得分:0)

我相信你可以通过

  

System.String,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089

进入Type.Parse()。我认为这是一个完全合格的类型名称。