Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Get Generic Type Name

Tags:

c#

generics

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

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

What I want, is a message box to pop up with List showing... how can I do that?

like image 753
Entity Avatar asked Nov 15 '10 14:11

Entity


4 Answers

You can implement an extension method to get the "friendly name" of a type, like this:

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

With this in your project, you can now say:

MessageBox.Show(t.GetFriendlyName());

And it will display "List<String>".

I know the OP didn't ask for the generic type parameters, but I prefer it that way. ;-)

Namespaces, standard aliases for built-in types, and use of StringBuilder left as an exercise for the reader. ;-)

like image 131
yoyo Avatar answered Oct 17 '22 12:10

yoyo


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"
}
like image 41
LukeH Avatar answered Oct 17 '22 11:10

LukeH


My take on yoyo's approach. Ensures more friendly names for primitives, handles arrays and is recursive to handle nested generics. Also unit tests.

    private static readonly Dictionary<Type, string> _typeToFriendlyName = new Dictionary<Type, string>
    {
        { typeof(string), "string" },
        { typeof(object), "object" },
        { typeof(bool), "bool" },
        { typeof(byte), "byte" },
        { typeof(char), "char" },
        { typeof(decimal), "decimal" },
        { typeof(double), "double" },
        { typeof(short), "short" },
        { typeof(int), "int" },
        { typeof(long), "long" },
        { typeof(sbyte), "sbyte" },
        { typeof(float), "float" },
        { typeof(ushort), "ushort" },
        { typeof(uint), "uint" },
        { typeof(ulong), "ulong" },
        { typeof(void), "void" }
    };

    public static string GetFriendlyName(this Type type)
    {
        string friendlyName;
        if (_typeToFriendlyName.TryGetValue(type, out friendlyName))
        {
            return friendlyName;
        }

        friendlyName = type.Name;
        if (type.IsGenericType)
        {
            int backtick = friendlyName.IndexOf('`');
            if (backtick > 0)
            {
                friendlyName = friendlyName.Remove(backtick);
            }
            friendlyName += "<";
            Type[] typeParameters = type.GetGenericArguments();
            for (int i = 0; i < typeParameters.Length; i++)
            {
                string typeParamName = typeParameters[i].GetFriendlyName();
                friendlyName += (i == 0 ? typeParamName : ", " + typeParamName);
            }
            friendlyName += ">";
        }

        if (type.IsArray)
        {
            return type.GetElementType().GetFriendlyName() + "[]";
        }

        return friendlyName;
    }

[TestFixture]
public class TypeHelperTest
{
    [Test]
    public void TestGetFriendlyName()
    {
        Assert.AreEqual("string", typeof(string).FriendlyName());
        Assert.AreEqual("int[]", typeof(int[]).FriendlyName());
        Assert.AreEqual("int[][]", typeof(int[][]).FriendlyName());
        Assert.AreEqual("KeyValuePair<int, string>", typeof(KeyValuePair<int, string>).FriendlyName());
        Assert.AreEqual("Tuple<int, string>", typeof(Tuple<int, string>).FriendlyName());
        Assert.AreEqual("Tuple<KeyValuePair<object, long>, string>", typeof(Tuple<KeyValuePair<object, long>, string>).FriendlyName());
        Assert.AreEqual("List<Tuple<int, string>>", typeof(List<Tuple<int, string>>).FriendlyName());
        Assert.AreEqual("Tuple<short[], string>", typeof(Tuple<short[], string>).FriendlyName());
    }
}
like image 26
Nick Avatar answered Oct 17 '22 12:10

Nick


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

like image 10
Johannes Rudolph Avatar answered Oct 17 '22 12:10

Johannes Rudolph