如何解析格式为List< int>的C#样式泛型类型名称?或字典< string,int>甚至更复杂的Dictionary< string,Dictionary< System.String,int []>>.假设这些名称是字符串,实际上可能不代表现有类型.它应该能够很容易地解析BogusClass< A,B,Vector< C>>.为了清楚起见,我对解析格式为List`1 [[System.Int32]]的.NET内部类型名称不感兴趣,但实际的C#类型名称就像它们出现在源代码中一样,有或没有使用点的命名空间限定符符号.
正则表达式是因为这些是嵌套结构.我想也许System.CodeDom.CodeTypeReference构造函数会为我解析它,因为它有字符串BaseType和CodeTypeReferenceCollection TypeArguments成员,但那些显然需要手动设置.
CodeTypeReference是我需要的一种结构:
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 } }
框架中是否有任何现有的类来实现这种类型名称解析?如果没有,我将如何解析这个?
解决方法
回答自己的问题.我写了下面的类来实现我需要的结果;给它一个旋转.
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",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,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() );
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: }