开发者

Get GenericType-Name in good format using Reflection on C#

I need to get the name of generic-type in form of its declaration in code.

For example: For List<Int32> I want to get string "List<Int32>". Standart property Type.Name returns "List`1" in this situation.

EDIT: example was f开发者_C百科ixed


Using built-in functions and Linq this can be written

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

NOTE: In pre-4.0 versions of C#, string.Join requires explicit .ToArray():

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


Ok, I've done a bunch of research, and discovered that typeof(List) has "GetGenericArguments" which will get you the sub names. So I'd do it this way (for 1 generic type, if it is a multi it'll take a loop or something. I can post a function for that if requested.

Here is a function to do it with multiple generic arguments, handles 'nested' generic types. Edited again to make this use the Aggregate function:

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


That isn't too hard. ;-)

Okay, I'll bite... g The one below works recusively and displays primitive types w/o namespace (like the OP wrote):

  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))
            + ">";
  }

The resulting cleanedName looks like this: System.Collections.Generic.Dictionary<System.Collections.Generic.List<Int32>, ConsoleApplication2.Program+SomeType>


Old question, but I only have the need for this today. So I wrote an extension method that can output nice looking C#-formatted generic name that can handle multilevel nested generic types.

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('>');
    }
}


If you don't remove the namespace names, just say:

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

and if you do, say:

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


Another example I just wrote myself before stumbling here.

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


Well, that's because the name of the type in .NET actually IS List'1. The "'1" is the so called arity of the generic, and it tells you how many type parameters there are.

It's needed so that you can create more then 1 generic type with the same "name" but a different number of generic type parameters.

For example, there are more than 1 type "called" System.Action. The real names of these are System.Action'1, System.Action'2, System.Action'3 etc.

So, if you know that your type is generic, you can assume that there is this 'XX at the end of the name, so you could just cut this part away, for example like this:

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

PS: Please replace ' with `.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜