如何解析C#泛型类型的名字呢? [英] How to parse C# generic type names?

查看:151
本文介绍了如何解析C#泛型类型的名字呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何解析C#风格格式的泛型类型名称列表< INT> 词典<字符串,整数> 或更为复杂的词典<字符串,字典< System.String,INT []>> 。假设这些名字是字符串,可实际上并不代表现有的类型。它应该很容易地能够解析 BogusClass< A,B,矢量< C>> 。需要明确的是,我在格式 List`1 [System.Int32] 解析.NET内部类型名称不感兴趣,但实际的C#类型名称,因为他们会出现在源代码中,使用或不使用点符号空间限定符。

How can I parse C#-style generic type names of the format List<int> or Dictionary<string,int> or even more complex Dictionary<string,Dictionary<System.String,int[]>>. Assume that these names are strings and may not actually represent existing types. It should just as easily be be able to parse BogusClass<A,B,Vector<C>>. To be clear, I am NOT interested in parsing .NET internal type names of the format List`1[[System.Int32]], but actual C# type names as they would appear in the source code, with or without namespace qualifiers using dot notation.

正则表达式,因为这些嵌套结构。我想也许System.CodeDom.CodeTypeReference构造函数解析它对于我来说,因为它有字符串BASETYPE CodeTypeReferenceCollection TypeArguments 成员,但这些显然需要手动设置

Regular expressions are out because these are nested structures. I thought perhaps the System.CodeDom.CodeTypeReference constructor would parse it for me since it has string BaseType and CodeTypeReferenceCollection TypeArguments members, but those apparently need to be set manually.

CodeTypeReference是我需要的那种结构:

CodeTypeReference is the kind of structure I need:

class TypeNameStructure
{
    public string Name;
    public TypeNameStructure[] GenericTypeArguments;
    public bool IsGenericType{get;}
    public bool IsArray{get;} //would be nice to detect this as well

    public TypeNameStructure( string friendlyCSharpName )
    {
       //Parse friendlyCSharpName into name and generic type arguments recursively
    }
}

有没有在框架来实现这种类型的名称解析的任何现有类?如果没有,我将如何去分析这个?

Are there any existing classes in the framework to achieve this kind of type name parsing? If not, how would I go about parsing this?

推荐答案

回答自己的问题。我写了下面的类实现我想要的结果; 。给它一个旋

Answering own question. I wrote the following class achieve the results I need; give it a spin.

public class TypeName
{
    public string Name;
    public bool IsGeneric;
    public List<ArrayDimension> ArrayDimensions;
    public List<TypeName> TypeArguments;

    public class ArrayDimension
    {
        public int Dimensions;

        public ArrayDimension()
        {
            Dimensions = 1;
        }

        public override string ToString()
        {
            return "[" + new String(',', Dimensions - 1) + "]";
        }
    }

    public TypeName()
    {
        Name = null;
        IsGeneric = false;
        ArrayDimensions = new List<ArrayDimension>();
        TypeArguments = new List<TypeName>();
    }

    public static string MatchStructure( TypeName toMatch, TypeName toType )
    {
        return null;
    }

    public override string ToString()
    {
        string str = Name;
        if (IsGeneric)
            str += "<" + string.Join( ",", TypeArguments.Select<TypeName,string>( tn => tn.ToString() ) ) + ">";
        foreach (ArrayDimension d in ArrayDimensions)
            str += d.ToString();
        return str;
    }

    public string FormatForDisplay( int indent = 0 )
    {
        var spacing = new string(' ', indent );
        string str = spacing + "Name: " + Name + "\r\n" +
        spacing + "IsGeneric: " + IsGeneric + "\r\n" +
        spacing + "ArraySpec: " + string.Join( "", ArrayDimensions.Select<ArrayDimension,string>( d => d.ToString() ) ) + "\r\n";
        if (IsGeneric)
        {
            str += spacing + "GenericParameters: {\r\n" + string.Join( spacing + "},{\r\n", TypeArguments.Select<TypeName,string>( t => t.FormatForDisplay( indent + 4 ) ) ) + spacing + "}\r\n";
        }
        return str;
    }

    public static TypeName Parse( string name )
    {
        int pos = 0;
        bool dummy;
        return ParseInternal( name, ref pos, out dummy );
    }

    private static TypeName ParseInternal( string name, ref int pos, out bool listTerminated )
    {
        StringBuilder sb = new StringBuilder();
        TypeName tn = new TypeName();
        listTerminated = true;
        while (pos < name.Length)
        {
            char c = name[pos++];
            switch (c)
            {
                case ',':
                    if (tn.Name == null)
                        tn.Name = sb.ToString();
                    listTerminated = false;
                    return tn;
                case '>':
                    if (tn.Name == null)
                        tn.Name = sb.ToString();
                    listTerminated = true;
                    return tn;
                case '<':
                {
                    tn.Name = sb.ToString();
                    tn.IsGeneric = true;
                    sb.Length = 0;
                    bool terminated = false;
                    while (!terminated)
                        tn.TypeArguments.Add( ParseInternal( name, ref pos, out terminated ) );
                    var t = name[pos-1];
                    if (t == '>')
                        continue;
                    else
                        throw new Exception( "Missing closing > of generic type list." );
                }
                case '[':
                    ArrayDimension d = new ArrayDimension();
                    tn.ArrayDimensions.Add( d );
                analyzeArrayDimension: //label for looping over multidimensional arrays
                    if (pos < name.Length)
                    {
                        char nextChar = name[pos++];
                        switch (nextChar)
                        {
                            case ']':
                                continue; //array specifier terminated
                            case ',': //multidimensional array
                                d.Dimensions++;
                                goto analyzeArrayDimension;
                            default:
                                throw new Exception( @"Expecting ""]"" or "","" after ""["" for array specifier but encountered """ + nextChar + @"""." );
                        }
                    }
                    throw new Exception( "Expecting ] or , after [ for array type, but reached end of string." );
                default:
                    sb.Append(c);
                    continue;
            }
        }
        if (tn.Name == null)
            tn.Name = sb.ToString();
        return tn;
    }
}

如果我运行以下命令:

 Console.WriteLine( TypeName.Parse( "System.Collections.Generic.Dictionary<Vector<T>,int<long[]>[],bool>" ).ToString() );



它正确地产生下面的输出,代表类型名作为一个字符串:

It correctly produces the following output, representing the TypeName as a string:

Name: System.Collections.Generic.Dictionary
IsGeneric: True
ArraySpec:
GenericParameters: {
    Name: Vector
    IsGeneric: True
    ArraySpec:
    GenericParameters: {
        Name: T
        IsGeneric: False
        ArraySpec:
    }
},{
    Name: int
    IsGeneric: True
    ArraySpec: []
    GenericParameters: {
        Name: long
        IsGeneric: False
        ArraySpec: []
    }
},{
    Name: bool
    IsGeneric: False
    ArraySpec:
}

这篇关于如何解析C#泛型类型的名字呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆