2011-07-09 84 views
2

的C#声明是否有可能得到“C#名”与反射获得像类型:泛型类型

System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] 

我想获得:

List<String> 

是否有可能不分裂字符串?例如,使用反射。

谢谢!

+0

描述你想要达到的目标,我们会尝试向大家更加简单和可靠的解决方案 – abatishchev

+0

你可以建造它从类型,你通过反射得到它,类型有GetGenericArguements,可以帮助你建立它。 –

回答

2

是的,你可以做到这一点,而不诉诸分裂,解析或使用CodeDomCSharpCodeProvider处理字符串:

using CodeDom; 
using Microsoft.CSharp; 

// ... 

Type yourType = typeof(List<string>); // for example 

using (var provider = new CSharpCodeProvider()) 
{ 
    var typeRef = new CodeTypeReference(yourType); 
    Console.WriteLine(provider.GetTypeOutput(typeRef)); 
} 

(您可能需要做一些额外的字符串操作删除命名空间前缀。例如,如果要输出为List<string>而不是System.Collections.Generic.List<string>。)

+0

您的解决方案非常有趣,我会测试它。 thx – malinois

+0

我已经添加了命名空间的拆分。谢谢 ! – malinois

0

...斗而不破的字符串?

AFAIK,

1

您需要解析像一个字符串:

t`x[[a(,b,c,d)]] 

其中t为实际类型; x - 通用参数的数量; A,B,C,d,等等 - 通用aguments

6

不是直接的,但你可以检查该类型本身弄明白。

public static string TypeName(Type t) { 
    if (!t.IsGenericType) return t.Name; 

    StringBuilder ret = new StringBuilder(); 
    ret.Append(t.Name).Append("<"); 

    bool first = true; 
    foreach(var arg in t.GetGenericArguments()) { 
     if (!first) ret.Append(", "); 
     first = false; 

     ret.Append(TypeName(arg)); 
    } 

    ret.Append(">"); 
    return ret.ToString(); 
} 
+0

@Lasse:哎呀!你完全正确地认为它应该超出if块(尽管我不同意它属于底层)。你也可以用Linq做得更好,尽管我不知道如何(递归和全部)。 –

+0

我删除了我的评论,因为它至少部分过时。而对于LINQ的一部分,这里的循环中如何实现:'ret.Append(。的string.join( “” t.GetGenericArguments()选择(T =>类型名(T))ToArray的())); ' –

+0

哦,我明白了,你的意思是用LINQ替换函数的主体。那么,请随时发布你自己的答案(我不会为我自己偷窃,因为这是你的工作!) –

0

您可以检查该类型以确定它是否嵌套,以及它是通用构造的还是基元类型。特别是我已经意识到嵌套的泛型类型在类型名称字符串的末尾列出了它的泛型参数。这在文档Type.GetType Method (String)中提到。

我已经部分解决的任务,我的解决方案通过下面的测试。

 [TestMethod] 
     public void Tests() 
     { 

      Assert.AreEqual("int",typeof(int).ToCSharpMethodReturnTypeName()); 
      Assert.AreEqual("int[]",typeof(int[]).ToCSharpMethodReturnTypeName()); 
      Assert.AreEqual("int?", typeof(int?).ToCSharpMethodReturnTypeName()); 

      Assert.AreEqual("UnitTypeFriendlyNamesExtensionsTest.Inner2<string,IDictionary<string,object>>.SubInner<int,List<byte[]>,object>", typeof(Inner2<string,IDictionary<string,object>>.SubInner<int,List<byte[]>,object>).ToCSharpMethodReturnTypeName()); 

      Assert.ThrowsException<NotImplementedException>(()=> typeof(Inner2<string, IDictionary<string, object>>.SubInner<int, List<byte[]>, object>).DeclaringType.ToCSharpMethodReturnTypeName()); 

      var t = typeof(TestGenericReturnType<DateTime>); 
      var m = t.GetMethod("GetService"); 
      var tt = m.ReturnType; 

      Assert.AreEqual("DateTime",tt.ToCSharpMethodReturnTypeName()); 

      Assert.AreEqual("IDictionary<string,object>",typeof(IDictionary<string,object>).ToCSharpMethodReturnTypeName()); 
      Assert.AreEqual("IList<int[]>",typeof(IList<int[]>).ToCSharpMethodReturnTypeName()); 
      Assert.AreEqual("UnitTypeFriendlyNamesExtensionsTest.Astruc?",typeof(Astruc?).ToCSharpMethodReturnTypeName()); 
      Assert.AreEqual("UnitTypeFriendlyNamesExtensionsTest.Inner", typeof(Inner).ToCSharpMethodReturnTypeName()); 
     } 

extensions类处理嵌套和泛型构造类型以及基元类型。

public static class TypeFriendlyNamesExtensions 
{ 
    private static readonly Dictionary<Type, string> TypeToFriendlyName = new Dictionary<Type, string> 
    { 
     {typeof(string), "string"}, 
     {typeof(object), "object"}, 
     {typeof(bool), "bool"}, 
     {typeof(byte), "byte"}, 
     {typeof(char), "char"}, 
     {typeof(decimal), "decimal"}, 
     {typeof(double), "double"}, 
     {typeof(short), "short"}, 
     {typeof(int), "int"}, 
     {typeof(long), "long"}, 
     {typeof(sbyte), "sbyte"}, 
     {typeof(float), "float"}, 
     {typeof(ushort), "ushort"}, 
     {typeof(uint), "uint"}, 
     {typeof(ulong), "ulong"}, 
     {typeof(void), "void"} 
    }; 

    public static string ToCSharpMethodReturnTypeName(this Type type) 
    { 
     var sb = new StringWriter(); 
     ToCSharpNameEntry2(sb, type); 
     return sb.ToString(); 
    } 

    private static void ToCSharpNameEntry2(TextWriter sb, Type type0) 
    { 
     var list = GetContainingTypeList(type0); 
     var usedGenericArgumentCounter = 0; 

     HandleNestedLevel(sb, list, 0, ref usedGenericArgumentCounter); 
     foreach (var ix in Enumerable.Range(1, list.Count - 1)) 
     { 
      sb.Write("."); 
      HandleNestedLevel(sb, list, ix, ref usedGenericArgumentCounter); 
     } 
    } 

    private static void HandleNestedLevel(TextWriter sb, IReadOnlyList<Type> list, int ix, 
     ref int usedGenericArgumentCounter) 
    { 
     var type = list[ix]; 
     if (TypeToFriendlyName.TryGetValue(type, out string fname)) 
     { 
      sb.Write(fname); 
      return; 
     } 
     if (type.IsGenericParameter) 
     { 
      sb.Write(type.Name); 
      return; 
     } 
     if (type.IsArray) 
     { 
      ToCSharpNameEntry2(sb, type.GetElementType()); 
      sb.Write("[]"); 
      return; 
     } 

     if (type.IsGenericType) 
     { 
      var innermostType = list[list.Count - 1]; 
      var args = list[list.Count - 1].GenericTypeArguments; 
      if (!type.IsConstructedGenericType) 
      { 
       if (innermostType.IsConstructedGenericType) 
       { 
        var sname = GetSname(type); 
        sb.Write(sname); 
        sb.Write("<"); 
        ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]); 
        var loopCounter = ((TypeInfo) type).GenericTypeParameters.Length; 
        while (0 < --loopCounter) 
        { 
         sb.Write(","); 
         ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]); 
        } 
        sb.Write(">"); 
        return; 
       } 
       throw new NotImplementedException(); 
      } 
      if (typeof(Nullable<>) == type.GetGenericTypeDefinition()) 
      { 
       ToCSharpNameEntry2(sb, args[0]); 
       sb.Write("?"); 
       return; 
      } 
      var cname = GetSname(type); 
      sb.Write(cname); 
      sb.Write("<"); 
      ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]); 
      while (usedGenericArgumentCounter < args.Length) 
      { 
       sb.Write(","); 
       ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]); 
      } 
      sb.Write(">"); 
      return; 
     } 
     if (type.IsPointer) 
     { 
      ToCSharpNameEntry2(sb, type); 
      sb.Write("*"); 
      return; 
     } 
     sb.Write(type.Name); 
    } 

    private static string GetSname(Type type) 
    { 
     var name = type.Name; 
     return name.Substring(0, name.IndexOf('`')); 
    } 

    private static List<Type> GetContainingTypeList(Type type) 
    { 
     var list = new List<Type> {type}; 
     var t = type; 
     while (t.IsNested) 
     { 
      t = t.DeclaringType; 
      list.Insert(0, t); 
     } 
     return list; 
    } 

    private static void ToCSharpNameEntry(StringBuilder sb, Type type) 
    { 
     var genericTypeArguments = type.GenericTypeArguments; 
     var usedGenericTypeCounter = 0; 
     ToCSharpNameRecursive(sb, type, genericTypeArguments, ref usedGenericTypeCounter); 
    } 

    private static void ToCSharpNameRecursive(StringBuilder sb, Type type, IReadOnlyList<Type> genericTypeArguments, 
     ref int genericTypesCounter) 
    { 
     if (TypeToFriendlyName.TryGetValue(type, out string res)) 
     { 
      sb.Append(res); 
      return; 
     } 

     HandleNonPriminiveTypes(sb, type, genericTypeArguments, ref genericTypesCounter); 
    } 

    private static void HandleNonPriminiveTypes(StringBuilder sb, Type type, IReadOnlyList<Type> typeGenericTypeArguments, 
     ref int genericTypesCounter) 
    { 
     var list = new List<Type>(); 
     var t = type; 
     list.Add(t); 
     while (t.IsNested) 
     { 
      t = t.DeclaringType; 
      list.Add(t); 
     } 
     list.Reverse(); 
     foreach (var type1 in list) 
     { 
      HandleNestedLevel(sb, type1, typeGenericTypeArguments, ref genericTypesCounter); 
      sb.Append("."); 
     } 
     sb.Length -= 1; 
    } 

    private static void HandleNestedLevel(StringBuilder sb, Type type, IReadOnlyList<Type> typeGenericTypeArguments, 
     ref int genericTypesCounter) 
    { 
     var name = type.Name; 
     if (type.IsGenericType) 
     { 
      var info = type.GetTypeInfo(); 
      var def = info.GetGenericTypeDefinition(); 
      var psLength = info.IsConstructedGenericType 
       ? info.GenericTypeArguments.Length 
       : info.GenericTypeParameters.Length; 
      if (typeof(Nullable<>) == def) 
      { 
       var type1 = typeGenericTypeArguments[genericTypesCounter++]; 
       ToCSharpNameEntry(sb, type1); 
       sb.Append("?"); 
       return; 
      } 

      var n = name.Substring(0, name.IndexOf("`", StringComparison.InvariantCultureIgnoreCase)); 

      sb.Append(n); 
      sb.Append("<"); 
      for (var i = 0; i < psLength; i++) 
      { 
       ToCSharpNameEntry(sb, typeGenericTypeArguments[genericTypesCounter++]); 
       sb.Append(","); 
      } 
      sb.Length -= 1; 
      sb.Append(">"); 
      return; 
     } 
     if (type.IsArray) 
     { 
      var type1 = type.GetElementType(); 
      ToCSharpNameEntry(sb, type1); 
      sb.Append("[]"); 
      return; 
     } 
     sb.Append(name); 
    } 
} 

我使用扩展方法在撰写原文由罗斯林编译