views:

81

answers:

3

Hello everybody. 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 fixed

A: 

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 `.

Maximilian Mayerl
Sorry, there was a mistake in my example. I need to get argument of generic type (in my example: Int32)
DreamWalker
+2  A: 

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();
}
Erich
Should be enhanced a bit. The generic argument should be formatted the same way, it could be a generic type again. Of course it should support many generic arguments.
Stefan Steinegger
I was in the process of typing a more complex version which handled that and multiples, which I just posted.
Erich
Edited again to use aggregates. Check the edit history if you want the 'old' version. Functionality is identical, but I wanted to figure out how aggregate worked, and this was a good way to learn :)
Erich
When you already use a stringbuilder, you might just as well use it in your aggregate call: sb.Append(t.Name.Substring(0, t.Name.LastIndexOf("`"))); int i = 0 t.GetGenericArguments() .Aggregate(sb, (a, type) => a.Append((i++ == 0 ? "<" : ",") .Append(GetFullName(type)));
Robert Giesecke
+1  A: 

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>

Robert Giesecke