简体   繁体   English

获取没有任何泛型信息的类型名称

[英]Get type name without any generics info

If I write:如果我写:

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

It will write:它会写:

List`1列表`1

I want it to write just:我希望它只写:

List列表

How can I do that?我怎样才能做到这一点? Is there a smarter way to do it without having to use Substring or similar string manipulation functions?有没有更聪明的方法来做到这一点,而不必使用Substring或类似的字符串操作函数?

No, it makes perfect sense for it to include the generic arity in the name - because it's part of what makes the name unique (along with assembly and namespace, of course). 不,在名称中包含泛型Arial是很有意义的-因为它是使名称唯一的一部分(当然,还有程序集和名称空间)。

Put it this way: System.Nullable and System.Nullable<T> are very different types. 这样说: System.NullableSystem.Nullable<T>是非常不同的类型。 It's not expected that you'd want to confuse the two... so if you want to lose information, you're going to have to work to do it. 没想到您会混淆这两个……因此,如果您丢失信息,就必须努力做到这一点。 It's not very hard, of course, and can be put in a helper method: 当然,它不是很困难,可以放在辅助方法中:

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

Then: 然后:

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

If someone is interested, I created some extensionmethods for this problem that create a more "readable" string 如果有人感兴趣,我针对此问题创建了一些扩展方法,这些方法创建了更“易读”的字符串

it produces something like 它产生类似

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

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

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

 Console.WriteLine(type.GetGenericTypeDefinition().UnderlyingSystemType.Name)
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)}>";
}

Example output:示例输出:

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

Here's the code from this answer inside a static class and namespace for easier copy-and-pasting.这是静态类和命名空间中此答案中的代码,以便于复制和粘贴。

Also, there's another extension method to get the type its namespace.此外,还有另一种扩展方法来获取类型的命名空间。

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

The easiest way I can think of as of C#6(I think) you can do the following:我能想到的最简单的方法是 C#6(我认为),您可以执行以下操作:

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

This will print:这将打印:

List
Dictionary

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM