2010-11-15 171 views
29

我需要某种方式来获取类型的名称,当type.IsGenericType = trueC#获取泛型类型名称

Type t = typeof(List<String>); 
    MessageBox.Show(..?..); 

我想要的,是一个消息框,List描述了...我怎么能做到这一点弹出?

回答

29
Type t = ...; 

if (t.IsGenericType) 
{ 
    Type g = t.GetGenericTypeDefinition(); 

    MessageBox.Show(g.Name);        // displays "List`1" 

    MessageBox.Show(g.Name.Remove(g.Name.IndexOf('`'))); // displays "List" 
} 
+4

如果你需要一个通用型的T型像'名单'你可以使用这样的事情't.GetGenericArguments()[0] .Name'。我不久前需要这个,并且无法在任何地方找到它。这将返回字符串,如果你有一个'List'列表' – 2016-03-31 00:27:01

38

您可以实现一个扩展方法来获得“友好名称“,如下所示:

public static class TypeNameExtensions 
{ 
    public static string GetFriendlyName(this Type type) 
    { 
     string friendlyName = type.Name; 
     if (type.IsGenericType) 
     { 
      int iBacktick = friendlyName.IndexOf('`'); 
      if (iBacktick > 0) 
      { 
       friendlyName = friendlyName.Remove(iBacktick); 
      } 
      friendlyName += "<"; 
      Type[] typeParameters = type.GetGenericArguments(); 
      for (int i = 0; i < typeParameters.Length; ++i) 
      { 
       string typeParamName = typeParameters[i].Name; 
       friendlyName += (i == 0 ? typeParamName : "," + typeParamName); 
      } 
      friendlyName += ">"; 
     } 

     return friendlyName; 
    } 
} 

有了这个项目,你现在可以说:

MessageBox.Show(t.GetFriendlyName()); 

它会显示“列表<字符串>”。

我知道OP没有要求泛型类型参数,但我更喜欢这种方式。 ;-)

命名空间和standard aliases for built-in types作为练习给读者。

+2

随着新的C#可爱,你现在可以在一个(虽然很长)的行中写反引号检查后的所有位,这也将处理嵌套泛型: 'friendlyName + = $“<{string.Join(”,“,type.GetGenericArguments()。Select(p => type.GetFriendlyName()))}>”' – joshcomley 2017-11-28 05:34:17

3

我改进了代码生成中使用的yoyos版本。 请注意,现在所有类型都被引用full qualified => global :: System.String。

  public static string GetFriendlyTypeName(Type type) 
      { 
       string friendlyName = type.Name; 
       if (type.IsGenericType) 
       { 
        int iBacktick = friendlyName.IndexOf('`'); 
        if (iBacktick > 0) 
        { 
         friendlyName = friendlyName.Remove(iBacktick); 
        } 
        friendlyName += "<"; 
        Type[] typeParameters = type.GetGenericArguments(); 
        for (int i = 0; i < typeParameters.Length; ++i) 
        { 
         string typeParamName = GetFriendlyTypeName(typeParameters[i]); 
         friendlyName += (i == 0 ? typeParamName : "," + typeParamName); 
        } 
        friendlyName += ">"; 
        friendlyName = "global::" + type.Namespace + "." + friendlyName; 
       } 
       else 
       { 
        friendlyName = "global::" + type.FullName; 
       } 

       return friendlyName.Replace('+', '.'); 
      } 
5
public static class TypeNameExtensions 
{ 
    public static string GetFriendlyName(this Type type) 
    { 
     var friendlyName = type.Name; 
     if (!type.IsGenericType) return friendlyName; 

     var iBacktick = friendlyName.IndexOf('`'); 
     if (iBacktick > 0) friendlyName = friendlyName.Remove(iBacktick); 

     var genericParameters = type.GetGenericArguments().Select(x => x.GetFriendlyName()); 
     friendlyName += "<" + string.Join(", ", genericParameters) + ">"; 

     return friendlyName; 
    } 
} 
14

我采取的对YOYO的做法。为基元确保更友好的名称,处理数组,并递归处理嵌套泛型。也是单元测试。

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 GetFriendlyName(this Type type) 
    { 
     string friendlyName; 
     if (_typeToFriendlyName.TryGetValue(type, out friendlyName)) 
     { 
      return friendlyName; 
     } 

     friendlyName = type.Name; 
     if (type.IsGenericType) 
     { 
      int backtick = friendlyName.IndexOf('`'); 
      if (backtick > 0) 
      { 
       friendlyName = friendlyName.Remove(backtick); 
      } 
      friendlyName += "<"; 
      Type[] typeParameters = type.GetGenericArguments(); 
      for (int i = 0; i < typeParameters.Length; i++) 
      { 
       string typeParamName = typeParameters[i].GetFriendlyName(); 
       friendlyName += (i == 0 ? typeParamName : ", " + typeParamName); 
      } 
      friendlyName += ">"; 
     } 

     if (type.IsArray) 
     { 
      return type.GetElementType().GetFriendlyName() + "[]"; 
     } 

     return friendlyName; 
    } 

[TestFixture] 
public class TypeHelperTest 
{ 
    [Test] 
    public void TestGetFriendlyName() 
    { 
     Assert.AreEqual("string", typeof(string).FriendlyName()); 
     Assert.AreEqual("int[]", typeof(int[]).FriendlyName()); 
     Assert.AreEqual("int[][]", typeof(int[][]).FriendlyName()); 
     Assert.AreEqual("KeyValuePair<int, string>", typeof(KeyValuePair<int, string>).FriendlyName()); 
     Assert.AreEqual("Tuple<int, string>", typeof(Tuple<int, string>).FriendlyName()); 
     Assert.AreEqual("Tuple<KeyValuePair<object, long>, string>", typeof(Tuple<KeyValuePair<object, long>, string>).FriendlyName()); 
     Assert.AreEqual("List<Tuple<int, string>>", typeof(List<Tuple<int, string>>).FriendlyName()); 
     Assert.AreEqual("Tuple<short[], string>", typeof(Tuple<short[], string>).FriendlyName()); 
    } 
} 
+0

不错,我在我的codegen现在呢! – Karle 2016-03-03 12:34:26

+0

这是否编译?我不得不调整一下。编辑进行更正。 – Humberto 2016-05-18 17:49:26

+2

你忘记了可为空。为了美化可空数据,你应该使用如下的代码: 'if(type.GetGenericTypeDefinition()== typeof(Nullable <>)) return type.GetGenericArguments()。First()。GetFriendlyName()+“?”;' – 2017-04-06 08:58:09

0

这是我对此的看法。因为我所看到的,它始终存在,所以我没有进行反向检查。你可以添加它,如果你想,但我喜欢保持简单。

public static string GetFriendlyName(this Type type) 
{ 
    if (type.IsGenericType) 
    { 
     var name = type.Name.Substring(0, type.Name.IndexOf('`')); 
     var types = string.Join(",", type.GetGenericArguments().Select(GetFriendlyName)); 
     return $"{name}<{types}>"; 
    } 
    else 
    { 
     return type.Name; 
    } 
}