C#获取通用类型名称

时间:2010-11-15 14:54:27

标签: c# generics

type.IsGenericType = true时,我需要一些方法来获取类型的名称。

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

我想要的是一个弹出消息框List,显示......我该怎么做?

9 个答案:

答案 0 :(得分:53)

您可以实施一种扩展方法来获取友好名称&#34;一种类型,如:

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 = GetFriendlyName(typeParameters[i]);
                friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
            }
            friendlyName += ">";
        }

        return friendlyName;
    }
}

在项目中使用此功能,您现在可以说:

MessageBox.Show(t.GetFriendlyName());

它将显示&#34; List&lt; String&gt;&#34;。

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

命名空间,standard aliases for built-in types和StringBuilder的使用留给读者练习。 ; - )

答案 1 :(得分:32)

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

答案 2 :(得分:16)

我对yoyo的看法。确保更原始的友好名称,处理数组,并递归处理嵌套泛型。还有单元测试。

{
    "query" : {
        "bool" : {
            "must" : [
                { "match" : { "custom_query_rep" : "user" } },
                { "match" : { "custom_query_rep" : "abc" } }
            ]
        }
    }
}

答案 3 :(得分:8)

假设您只是想看到它需要List<T>而不是List<string>

MessageBox.Show(t.GetGenericTypeDefinition().FullName)

请参阅http://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition.aspx

答案 4 :(得分:6)

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

答案 5 :(得分:5)

这是我对此的看法。我没有进行反复检查,因为我看到它总是在那里。如果你愿意,你可以添加它,但我喜欢简单。

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

答案 6 :(得分:3)

我在代码生成中使用了改进的yoyos版本。 请注意,现在所有类型都被引用为完全限定=&gt;全球:: 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('+', '.');
            }

答案 7 :(得分:2)

这是一个基于先前答案的完整实现,同时支持别名(包括Nullable)和数组:

public static class TypeNameExtensions
{
    public static string GetFriendlyName(this Type type, bool aliasNullable = true, bool includeSpaceAfterComma = true)
    {
        TryGetInnerElementType(ref type, out string arrayBrackets);
        if (!TryGetNameAliasNonArray(type, out string friendlyName))
        {
            if (!type.IsGenericType)
            {
                friendlyName = type.Name;
            }
            else
            {
                if (aliasNullable && type.GetGenericTypeDefinition() == typeof(System.Nullable<>))
                {
                    string generics = GetFriendlyName(type.GetGenericArguments()[0]);
                    friendlyName = generics + "?";
                }
                else
                {
                    string generics = GetFriendlyGenericArguments(type, includeSpaceAfterComma);
                    int iBacktick = type.Name.IndexOf('`');
                    friendlyName = (iBacktick > 0 ? type.Name.Remove(iBacktick) : type.Name)
                        + $"<{generics}>";
                }
            }
        }
        return friendlyName + arrayBrackets;
    }

    public static bool TryGetNameAlias(this Type type, out string alias)
    {
        TryGetInnerElementType(ref type, out string arrayBrackets);
        if (!TryGetNameAliasNonArray(type, out alias))
            return false;
        alias += arrayBrackets;
        return true;
    }

    private static string GetFriendlyGenericArguments(Type type, bool includeSpaceAfterComma)
        => string.Join(
            includeSpaceAfterComma ? ", " : ",",
            type.GetGenericArguments().Select(t => t.GetFriendlyName())
            );

    private static bool TryGetNameAliasNonArray(Type type, out string alias)
        => (alias = TypeAliases[(int)Type.GetTypeCode(type)]) != null
        && !type.IsEnum;

    private static bool TryGetInnerElementType(ref Type type, out string arrayBrackets)
    {
        arrayBrackets = null;
        if (!type.IsArray)
            return false;
        do
        {
            arrayBrackets += "[" + new string(',', type.GetArrayRank() - 1) + "]";
            type = type.GetElementType();
        }
        while (type.IsArray);
        return true;
    }

    private static readonly string[] TypeAliases = {
        "void",     // 0
        null,       // 1 (any other type)
        "DBNull",   // 2
        "bool",     // 3
        "char",     // 4
        "sbyte",    // 5
        "byte",     // 6
        "short",    // 7
        "ushort",   // 8
        "int",      // 9
        "uint",     // 10
        "long",     // 11
        "ulong",    // 12
        "float",    // 13
        "double",   // 14
        "decimal",  // 15
        null,       // 16 (DateTime)
        null,       // 17 (-undefined-)
        "string",   // 18
    };
}

经过废话测试,例如:

var type = typeof(Dictionary<string[,], List<int?[,][]>[,,]>[]);
var name = type.GetFriendlyName();
Console.WriteLine(name);

它确实返回:"Dictionary<string[,], List<int?[,][]>[,,]>[]"


编辑:已更新,可以正确处理enum类型。

答案 8 :(得分:1)

我知道这是一个古老的问题,但是我和一位同事以及我自己需要做一些智能感知/罗斯林工作。最佳解决方案似乎是Ali's解决方案,但不适用于嵌套类型:

    int i = 1; //would work
    List<string> listTest = new List<string>(); //would work
    Dictionary<string, int> dictTest = new Dictionary<string, int>(); //would work
    Dictionary<int, List<string>> nestTest = new Dictionary<int, List<string>>(); //would fail
    Dictionary<int, List<Dictionary<string, List<object>>>> superNestTest = new Dictionary<int, List<Dictionary<string, List<object>>>>(); //would fail
    Dictionary<int, List<Dictionary<string, int>>> superNestTest2 = new Dictionary<int, List<Dictionary<string, int>>>(); //would fail

为了解决这些问题,我将该函数转换为递归方法:

public static class TypeExtensions
{
    public static string GetFriendlyName(this Type type)
    {
        string friendlyName = type.FullName;
        if (type.IsGenericType)
        {
            friendlyName = GetTypeString(type);
        }
        return friendlyName;
    }

    private static string GetTypeString(Type type)
    {
        var t = type.AssemblyQualifiedName;

        var output = new StringBuilder();
        List<string> typeStrings = new List<string>();  

        int iAssyBackTick = t.IndexOf('`') + 1;
        output.Append(t.Substring(0, iAssyBackTick - 1).Replace("[", string.Empty));
        var genericTypes = type.GetGenericArguments();

        foreach (var genType in genericTypes)
        {
            typeStrings.Add(genType.IsGenericType ? GetTypeString(genType) : genType.ToString());
        }

        output.Append($"<{string.Join(",", typeStrings)}>");
        return output.ToString();
    }
}

在前面的示例/测试用例中运行会产生以下输出:

System.Int32
System.Collections.Generic.List<System.String>
System.Collections.Generic.Dictionary<System.String,System.Int32>
System.Collections.Generic.Dictionary<System.Int32,System.Collections.Generic.List<System.String>>
System.Collections.Generic.Dictionary<System.Int32,System.Collections.Generic.List<System.Collections.Generic.Dictionary<System.String,System.Collections.Generic.List<System.Object>>>>
System.Collections.Generic.Dictionary<System.Int32,System.Collections.Generic.List<System.Collections.Generic.Dictionary<System.String,System.Int32>>>

我花了一些时间尝试解决嵌套类型问题,因此想在此处进行记录,以确保将来其他任何人都可以节省一些时间(和麻烦!)。我还检查了性能,它以毫秒为单位完成(在最后一种情况下为8毫秒:

  

效果结果
  (原始方案列表中使用的变量名称)
  "i" | 43uS
  "listTest" | 3uS
  "dictTest" | 2uS
  "nestTest" | 5uS
  "superNestTest" | 9uS
  "superNestTest2" | 9uS
  在每种情况下执行上述代码200次后的平均次数