【问题标题】:Get GenericType-Name in good format using Reflection on C#使用 C# 上的反射以良好的格式获取 GenericType-Name
【发布时间】:2010-12-04 17:21:34
【问题描述】:

我需要以代码中声明的形式获取泛型类型的名称。

例如: 对于 List,我想获取字符串“List”。 在这种情况下,标准属性 Type.Name 返回“List`1”。

编辑:示例已修复

【问题讨论】:

    标签: c# .net reflection


    【解决方案1】:

    嗯,这是因为 .NET 中的类型名称实际上是 List'1。 “'1”是泛型的所谓arity,它告诉你有多少类型参数。

    这样您就可以创建超过 1 个具有相同“名称”但泛型类型参数数量不同的泛型类型。

    例如,有不止一种类型“称为”System.Action。它们的真实名称是 System.Action'1、System.Action'2、System.Action'3 等。

    所以,如果你知道你的类型是通用的,你可以假设名字的末尾有这个 'XX,所以你可以把这部分删掉,例如这样:

    string strTypeName = typeof(List<>).Name.Substring(0, typeof(List<>).Name.LastIndexOf("`"));
    

    PS:请用`替换'。

    【讨论】:

    • 对不起,我的例子中有一个错误。我需要获取泛型类型的参数(在我的示例中:Int32)
    • 这个答案不再相关(在问题被编辑之后)。
    【解决方案2】:

    好的,我做了很多研究,发现 typeof(List) 有“GetGenericArguments”,它可以让你得到子名称。所以我会这样做(对于 1 个泛型类型,如果它是一个 multi 它将需要一个循环或其他东西。如果需要,我可以发布一个函数。

    这是一个使用多个泛型参数来处理“嵌套”泛型类型的函数。再次编辑以使用 Aggregate 函数:

    static string GetFullName(Type t)
    {
        if (!t.IsGenericType)
            return t.Name;
        StringBuilder sb=new StringBuilder();
    
        sb.Append(t.Name.Substring(0, t.Name.LastIndexOf("`")));
        sb.Append(t.GetGenericArguments().Aggregate("<",
    
            delegate(string aggregate,Type type)
                {
                    return aggregate + (aggregate == "<" ? "" : ",") + GetFullName(type);
                }  
            ));
        sb.Append(">");
    
        return sb.ToString();
    }
    

    【讨论】:

    • 应该加强一点。泛型参数的格式应该相同,它可以再次是泛型类型。当然它应该支持许多通用参数。
    • 我正在输入一个更复杂的版本来处理这个问题和倍数,我刚刚发布了。
    • 再次编辑以使用聚合。如果您想要“旧”版本,请检查编辑历史记录。功能是相同的,但我想弄清楚聚合是如何工作的,这是学习的好方法:)
    • 如果你已经使用了一个字符串生成器,你也可以在你的聚合调用中使用它: sb.Append(t.Name.Substring(0, t.Name.LastIndexOf("`")) ); int i = 0 t.GetGenericArguments() .Aggregate(sb, (a, type) => a.Append((i++ == 0 ? "
    【解决方案3】:

    这并不难。 ;-)

    好吧,我会咬一口... g 下面的一个循环工作并显示没有命名空间的原始类型(就像 OP 写的那样):

      static string PrettyPrintGenericTypeName(Type typeRef)
      {
         var rootType = typeRef.IsGenericType
            ? typeRef.GetGenericTypeDefinition()
            : typeRef;
    
         var cleanedName = rootType.IsPrimitive
                              ? rootType.Name
                              : rootType.ToString();
    
         if (!typeRef.IsGenericType)
            return cleanedName;
         else
            return cleanedName.Substring(0,
                                         cleanedName.LastIndexOf('`'))
                + typeRef.GetGenericArguments()
                         .Aggregate("<",
                                    (r, i) =>
                                       r
                                       + (r != "<" ? ", " : null)
                                       + PrettyPrintGenericTypeName(i))
                + ">";
      }
    

    生成的 cleanName 如下所示:System.Collections.Generic.Dictionary&lt;System.Collections.Generic.List&lt;Int32&gt;, ConsoleApplication2.Program+SomeType&gt;

    【讨论】:

      【解决方案4】:

      使用内置函数和Linq可以这样写

      static string PrettyTypeName(Type t)
      {
          if (t.IsArray)
          {
              return PrettyTypeName(t.GetElementType()) + "[]";
          }
      
          if (t.IsGenericType)
          {
              return string.Format(
                  "{0}<{1}>",
                  t.Name.Substring(0, t.Name.LastIndexOf("`", StringComparison.InvariantCulture)),
                  string.Join(", ", t.GetGenericArguments().Select(PrettyTypeName)));
          }
      
          return t.Name;
      }
      

      注意:在 C# 4.0 之前的版本中,string.Join 需要显式 .ToArray()

      string.Join(", ", t.GetGenericArguments().Select(PrettyTypeName).ToArray()));
      

      【讨论】:

      • 在 VS 2010 中使用 .NET 3.5(不确定哪个 C# 版本),t.GetGenericArguments().Select(PrettyTypeName) 给出编译器错误“cannot convert from 'System.Collections.Generic.IEnumerable' to ' string[]'" 修复:追加.ToArray()。添加到答案作为替代。
      • 不适用于PrettyTypeName(typeof(ICollection&lt;Tuple&lt;string, int, Tuple&lt;ICollection&lt;string&gt;,IList&gt;[]&gt;[]&gt;))。必须添加if (t.IsArray) return PrettyTypeName(t.GetElementType()) + "[]";
      【解决方案5】:

      另一个例子是我在遇到这里之前自己写的。

          private string PrettyPrintGenericTypeName(Type p)
          {
              if (p.IsGenericType) {
                  var simpleName = p.Name.Substring(0, p.Name.IndexOf('`'));
                  var genericTypeParams = p.GenericTypeArguments.Select(PrettyPrintGenericTypeName).ToList();
                  return string.Format("{0}<{1}>", simpleName, string.Join(", ", genericTypeParams));
              } else {
                  return p.Name;
              }
          }
      

      【讨论】:

        【解决方案6】:

        老问题,但我今天才需要这个。所以我写了一个扩展方法,它可以输出漂亮的 C# 格式的泛型名称,可以处理多级嵌套泛型类型。

        using System;
        using System.Text;
        
        public static class TypeExtensions
        {
            public static string GetNiceName(this Type type, bool useFullName = false)
            {
                if (!type.IsGenericType) {
                    return type.Name;
                }
        
                var typeNameBuilder = new StringBuilder();
                GetNiceGenericName(typeNameBuilder, type, useFullName);
                return typeNameBuilder.ToString();
            }
        
            static void GetNiceGenericName(StringBuilder sb, Type type, bool useFullName)
            {
                if (!type.IsGenericType) {
                    sb.Append(useFullName ? type.FullName : type.Name);
                    return;
                }
        
                var typeDef = type.GetGenericTypeDefinition();
                var typeName = useFullName ? typeDef.FullName : typeDef.Name;
                sb.Append(typeName);
                sb.Length -= typeName.Length - typeName.LastIndexOf('`');
                sb.Append('<');
                foreach (var typeArgument in type.GenericTypeArguments) {
                    GetNiceGenericName(sb, typeArgument, useFullName);
                    sb.Append(", ");
                }
                sb.Length -= 2;
                sb.Append('>');
            }
        }
        

        【讨论】:

          【解决方案7】:

          如果您不删除命名空间名称,只需说:

          Regex.Replace(""+@type, @"`\d+\[", "<").Replace("]", ">");
          

          如果你这样做了,说:

          Regex.Replace(Regex.Replace(""+@type, @"`\d+\[", "<").Replace("]", ">"), @"\w+\.", "")
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-15
            • 2011-02-04
            • 1970-01-01
            • 1970-01-01
            • 2011-01-27
            相关资源
            最近更新 更多