如何使用reflection获得generics类型的正确文本定义?

我正在研究代码生成,并遇到了generics问题。 这是导致我出现问题的“简化”版本。

Dictionary dictionary = new Dictionary(); 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 

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

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

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

例:

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

由于@LukeH的评论 ,一个好的和干净的选择是

 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); } } 

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

 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(), new List(), new List>(), 0 }; Type t = testCases[0].GetType(); string text = t.GetCodeDefinition(); Console.WriteLine(text); } } 
 string text = dictionary.ToString(); 

提供几乎所要求的:

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

我不认为.NET有内置的东西可以做到这一点,所以你必须自己做。 我认为reflection类提供了足够的信息来重建这种forms的类型名称。

我相信你可以通过

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

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