How can I get the correct text definition of a generic type using reflection?

前端 未结 6 1334
萌比男神i
萌比男神i 2020-12-01 14:17

I am working on code generation and ran into a snag with generics. Here is a \"simplified\" version of what is causing me issues.

Dictionary

        
相关标签:
6条回答
  • 2020-12-01 14:34
    string text = dictionary.ToString();
    

    provides almost what you are asking for:

    System.Collections.Generic.Dictionary`2[System.String,System.DateTime]
    
    0 讨论(0)
  • 2020-12-01 14:37

    I don't think .NET has anything built-in that would do this, so you will have to do it yourself. I think that the reflection classes provide quite enough information to reconstruct the type name in this form.

    0 讨论(0)
  • 2020-12-01 14:46

    There is no built-in way to get this representation in the .Net Framework. Namely because there is no way to get it correct. There are a good number of constructs that are not representable in C# style syntax. For instance "<>foo" is a valid type name in IL but cannot be represented in C#.

    However, if you're looking for a pretty good solution it can be hand implemented fairly quickly. The below solution will work for most situations. It will not handle

    1. Nested Types
    2. Illegal C# Names
    3. Couple of other scenarios

    Example:

    public static string GetFriendlyTypeName(Type type) {
        if (type.IsGenericParameter)
        {
            return type.Name;
        }
    
        if (!type.IsGenericType)
        {
            return type.FullName;
        }
    
        var builder = new System.Text.StringBuilder();
        var name = type.Name;
        var index = name.IndexOf("`");
        builder.AppendFormat("{0}.{1}", type.Namespace, name.Substring(0, index));
        builder.Append('<');
        var first = true;
        foreach (var arg in type.GetGenericArguments())
        {
            if (!first)
            {
                builder.Append(',');
            }
            builder.Append(GetFriendlyTypeName(arg));
            first = false;
        }
        builder.Append('>');
        return builder.ToString();
    }
    
    0 讨论(0)
  • 2020-12-01 14:49

    This evening I was toying a bit with extension methods and I tried to find an answer for your question. Here is the result: it's a no-warranty code. ;-)

    internal static class TypeHelper
    {
        private const char genericSpecialChar = '`';
        private const string genericSeparator = ", ";
    
        public static string GetCleanName(this Type t)
        {
            string name = t.Name;
            if (t.IsGenericType)
            {
                name = name.Remove(name.IndexOf(genericSpecialChar));
            }
            return name;
        }
    
        public static string GetCodeDefinition(this Type t)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0}.{1}", t.Namespace, t.GetCleanName());
            if (t.IsGenericType)
            {
                var names = from ga in t.GetGenericArguments()
                            select GetCodeDefinition(ga);
                sb.Append("<");
                sb.Append(string.Join(genericSeparator, names.ToArray()));
                sb.Append(">");
            }
            return sb.ToString();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            object[] testCases = { 
                                    new Dictionary<string, DateTime>(),
                                    new List<int>(),
                                    new List<List<int>>(),
                                    0
                                };
            Type t = testCases[0].GetType();
            string text = t.GetCodeDefinition();
            Console.WriteLine(text);
        }
    }
    
    0 讨论(0)
  • 2020-12-01 14:50

    I believe you can pass

    System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

    into Type.Parse(). That is a fully qualified type name, I think.

    0 讨论(0)
  • 2020-12-01 14:51

    A good and clean alternative, thanks to @LukeH's comment, is

    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using Microsoft.CSharp;
    //...
    private string GetFriendlyTypeName(Type type)
    {
        using (var p = new CSharpCodeProvider())
        {
            var r = new CodeTypeReference(type);
            return p.GetTypeOutput(r);
        }
    }
    
    0 讨论(0)
提交回复
热议问题