3

I'm trying to get generic type in string I get something more like IL representation, I need the real source representation for emitting it.

Type t = typeof(Stack<string>);

string source = t.Name;        //Stack`1[System.String]
string source = t.ToString();  //System.Collections.Generic.Stack`1[System.String]

I just need:

string source //Stack<string>
jrbedard
  • 3,662
  • 5
  • 30
  • 34
JDOE
  • 45
  • 4
  • 1
    The IL representation and the C# representation of generic types do not use the same syntax, and VB is yet another story (`Stack(Of String)`). There is no "real source representation" for it therefore. – Lucero Sep 30 '16 at 21:05
  • Very unclear what you are trying to do... Something like http://stackoverflow.com/questions/9811456/generics-with-il may be of help... but you really don't need string representation of type to generate IL... – Alexei Levenkov Sep 30 '16 at 21:12
  • 2
    I disagree, his question is perfectly clear. He just has an incorrect idea of what IL looks like. He wants the output to be `Stack`. He doesn't want anything IL-related at all. –  Sep 30 '16 at 21:18

2 Answers2

3

I've got this extension method, GetPrettyName(). This is basically it:

public static string GetPrettyName(this Type type)
{
    var retval = type.Name;

    if (type.IsGenericType)
    {
        var genargNames = type.GetGenericArguments().Select(t => GetPrettyName(t));
        var idx = type.Name.IndexOf('`');
        var typename = (idx > 0) ? type.Name.Substring(0, idx) : type.Name;
        retval = String.Format("{0}.{1}<{2}>", type.Namespace, typename, String.Join(", ", genargNames));
    }
    else if (type.IsArray)
    {
        retval = GetPrettyName(type.GetElementType()) + "[]";
    }
    else if (String.IsNullOrEmpty(retval))
    {
        retval = type.Name;
    }

    return retval;
}

It operates recursively on each generic type parameter and builds out the full name in a format that's close to the code representation. It's good enough for our purposes (its just used in logging messages here). It can handle generics and arrays, but does not handle Entity Framework proxies that well.

  • Yes I think this is a good way to approach this - there's a few other things it doesn't support though, like multi-dimensional arrays (new List[1,2] etc should output List[,]), but otherwise looks good – David_001 Sep 30 '16 at 21:35
  • True enough. Adding support for multidimensional arrays shouldn't be too hard at all, though. Get the number of dimensions, add that many commas minus one between the brackets. We just never needed to support such things, as our code doesn't use them, IIRC. –  Sep 30 '16 at 21:52
  • Nested classes are also not supported. – Klocman Jul 04 '19 at 11:55
0

Here's a version of Amy's answer with support for nested classes and multi-dimensional arrays.

public static string GetSourceCodeRepresentation(this Type type)
{
    return GetSourceCodeRepresentationInt(type, new List<Type>());
}

private static string GetSourceCodeRepresentationInt(Type type, List<Type> travesed)
{
    travesed.Add(type);

    var prefixName = string.Empty;
    if (type.DeclaringType != null)
    {
        if (!travesed.Contains(type.DeclaringType))
            prefixName = GetSourceCodeRepresentationInt(type.DeclaringType, travesed) + ".";
    }
    else if (!string.IsNullOrEmpty(type.Namespace))
        prefixName = type.Namespace + ".";

    if (type.IsGenericType)
    {
        var genargNames = type.GetGenericArguments().Select(type1 => GetSourceCodeRepresentationInt(type1, new List<Type>()));
        var idx = type.Name.IndexOf('`');
        var typename = idx > 0 ? type.Name.Substring(0, idx) : type.Name;
        return $"{prefixName}{typename}<{string.Join(", ", genargNames.ToArray())}>";
    }

    if (type.IsArray)
    {
        return $"{GetSourceCodeRepresentation(type.GetElementType())}[{new string(Enumerable.Repeat(',', type.GetArrayRank() - 1).ToArray())}]";
    }

    return $"{prefixName}{type.Name}";
}
Klocman
  • 432
  • 4
  • 12