【问题标题】:Get type name without any generics info获取没有任何泛型信息的类型名称
【发布时间】:2011-06-17 13:09:59
【问题描述】:

如果我写:

var type = typeof(List<string>);
Console.WriteLine(type.Name);

它会写:

列表`1

我希望它只写:

列表

我该怎么做? 有没有更聪明的方法来做到这一点而无需使用Substring 或类似的字符串操作函数?

【问题讨论】:

  • 从 C# 6 开始,您可以使用 nameof(List&lt;string&gt;) 完成此操作

标签: c# .net generics reflection


【解决方案1】:

不,在名称中包含泛型是完全合理的 - 因为它是使名称独一无二的一部分(当然还有程序集和命名空间)。

这样说:System.NullableSystem.Nullable&lt;T&gt; 是非常不同的类型。预计您不会想要混淆这两者......因此,如果您想要丢失信息,则必须努力做到这一点。当然,这不是很难,可以放在辅助方法中:

public static string GetNameWithoutGenericArity(this Type t)
{
    string name = t.Name;
    int index = name.IndexOf('`');
    return index == -1 ? name : name.Substring(0, index);
}

然后:

var type = typeof(List<string>);
Console.WriteLine(type.GetNameWithoutGenericArity());

【讨论】:

【解决方案2】:

不,它没有,因为“generic-type-string”是类型名称的一部分。

【讨论】:

    【解决方案3】:

    如果有人感兴趣,我为这个问题创建了一些扩展方法,这些方法创建了一个更“可读”的字符串

    它会产生类似的东西

    List[string]
    outer.inner[other.whatever]
    IEnumerable[T0]
    Dictionary[string:int]
    

    测试here

    public static class TypeEx
    {
        public static string GetTypeName(this Type type)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));
    
            if (!type.IsGenericType)
                return type.GetNestedTypeName();
    
            StringBuilder stringBuilder = new StringBuilder();
            _buildClassNameRecursiv(type, stringBuilder);
            return stringBuilder.ToString();
        }
    
        private static void _buildClassNameRecursiv(Type type, StringBuilder classNameBuilder, int genericParameterIndex = 0)
        {
            if (type.IsGenericParameter)
                classNameBuilder.AppendFormat("T{0}", genericParameterIndex + 1);
            else if (type.IsGenericType)
            {
                classNameBuilder.Append(GetNestedTypeName(type) + "[");
                int subIndex = 0;
                foreach (Type genericTypeArgument in type.GetGenericArguments())
                {
                    if (subIndex > 0)
                        classNameBuilder.Append(":");
    
                    _buildClassNameRecursiv(genericTypeArgument, classNameBuilder, subIndex++);
                }
                classNameBuilder.Append("]");
            }
            else
                classNameBuilder.Append(type.GetNestedTypeName());
        }
    
        public static string GetNestedTypeName(this Type type)
        {
            if (type == null)
                throw new ArgumentNullException(nameof(type));
            if (!type.IsNested)
                return type.Name;
    
            StringBuilder nestedName = new StringBuilder();
            while(type != null)
            {
                if(nestedName.Length>0)
                    nestedName.Insert(0,'.');
    
                nestedName.Insert(0, _getTypeName(type));
    
                type = type.DeclaringType;
            }
            return nestedName.ToString();
        }
    
        private static string _getTypeName(Type type)
        {
            return type.IsGenericType ? type.Name.Split('`')[0]: type.Name;
        }
    }
    

    【讨论】:

      【解决方案4】:
      static void Main(string[] args)
      {
      
          Console.WriteLine(WhatIsMyType<IEnumerable<string>>());
          Console.WriteLine(WhatIsMyType<List<int>>());
          Console.WriteLine(WhatIsMyType<IList<int>>());
          Console.WriteLine(WhatIsMyType<List<ContentBlob>>());
          Console.WriteLine(WhatIsMyType<int[]>());
          Console.WriteLine(WhatIsMyType<ContentBlob>());
          Console.WriteLine(WhatIsMyType<Dictionary<string, Dictionary<int, int>>>());
      }
      
      public static string WhatIsMyType<T>()
      {
          return typeof(T).NameWithGenerics();
      }
      
      public static string NameWithGenerics(this Type type)
      {
          if (type == null)
              throw new ArgumentNullException(nameof(type));
      
          if (type.IsArray)
              return $"{type.GetElementType()?.Name}[]";
      
          if (!type.IsGenericType) 
              return type.Name;
      
          var name = type.GetGenericTypeDefinition().Name;
          var index = name.IndexOf('`');
          var newName = index == -1 ? name : name.Substring(0, index);
              
          var list = type.GetGenericArguments().Select(NameWithGenerics).ToList();
          return $"{newName}<{string.Join(",", list)}>";
      }
      

      示例输出:

      IEnumerable<String>
      List<Int32>
      IList<Int32>
      List<ContentBlob>
      Int32[]
      ContentBlob
      Dictionary<String,Dictionary<Int32,Int32>>
      

      【讨论】:

        【解决方案5】:

        这是来自this answer 的代码,位于静态类和命名空间中,以便于复制和粘贴。

        此外,还有另一种扩展方法可以获取类型的命名空间。

        using System;
        
        namespace TODO
        {
            public static class TypeExtensions
            {
                /// <summary>
                /// From: https://stackoverflow.com/a/6386234/569302
                /// </summary>
                public static string GetNameWithoutGenericArity(this Type t)
                {
                    string name = t.Name;
                    int index = name.IndexOf('`');
                    return index == -1 ? name : name.Substring(0, index);
                }
                public static string GetFullNameWithoutGenericArity(this Type t)
                {
                    var result = $"{t.Namespace}.{t.GetNameWithoutGenericArity()}";
                    return result;
                }
            }
        }
        

        【讨论】:

          【解决方案6】:

          我能想到的最简单的 C#6 方法(我认为)你可以执行以下操作:

          public static void Main(string[] args)
          {
              Console.WriteLine(nameof(List<int>));
              Console.WriteLine(nameof(Dictionary<int, int>));
          }
          

          这将打印:

          List
          Dictionary
          

          【讨论】:

            猜你喜欢
            • 2011-01-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-29
            • 1970-01-01
            • 2016-01-12
            相关资源
            最近更新 更多