C# Get Generic Type Name

前端 未结 9 1685
旧时难觅i
旧时难觅i 2020-11-30 06:09

I need some way to get the Name of a Type, when type.IsGenericType = true.

    Type t = typeof(List);
    MessageBox.         


        
相关标签:
9条回答
  • 2020-11-30 06:45

    Here is my take on this. I did not put the backtick check since for what I see, it's always there. You can add it if you want but I like to keep things simple.

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-30 06:47
    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"
    }
    
    0 讨论(0)
  • 2020-11-30 06:52

    Assuming you just want to see that its List<T> instead of List<string> you'd need to do:

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

    See http://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition.aspx

    0 讨论(0)
  • 2020-11-30 07:06
    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-30 07:06

    i have improved yoyos version for the usage in Code Generation. Note that all types are now referenced 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('+', '.');
                }
    
    0 讨论(0)
  • 2020-11-30 07:09

    Here is a complete implementation based on the previous answers supporting both Aliases (including Nullable) and Arrays:

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

    Tested with nonsense such as:

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

    And it does indeed return: "Dictionary<string[,], List<int?[,][]>[,,]>[]"


    Edit: Updated to properly handle enum types.

    0 讨论(0)
提交回复
热议问题