System.Type.FullName 的意外值
Posted
技术标签:
【中文标题】System.Type.FullName 的意外值【英文标题】:Unexpected value of System.Type.FullName 【发布时间】:2012-07-28 01:36:01 【问题描述】:我最近需要为任意类型构建 C# 特定名称(必须始终包含 global:: 说明符)并且遇到了以下问题:
// 1 - value: System.String[,,,][,,][,]
string unexpectedFullName = typeof( string[,][,,][,,,] ).FullName;
// 2 - value: System.String[,][,,][,,,]
string expectedFullName = Type.GetType( "System.String[,][,,][,,,]" ).FullName;
我期望在这两种情况下返回的值是相同的。但是,由于某种原因,值的与数组相关的部分似乎被颠倒了(案例 1)。这是预期的逆转行为吗?
【问题讨论】:
我以前遇到过这个;似乎在 C# 中您按照读取的顺序声明数组索引/维度,反射返回与其逻辑结构匹配的类型名称。毕竟,(C#)string[,][,,][,,,]
是 string
类型的值,它是一个 4 维数组(即string[,,,]
),它是一个 3 维数组(即 string[,,,][,,]
),它是一个 2维数组(即string[,,,][,,][,]
)。
他所说的一切^^^^。 c# 语法 (explained in depth here) 不需要匹配反射命名约定。因此,如果您正在处理反射:使用反射命名。在其他新闻中,嵌套类型不是Outer.Inner
,而是Outer+Inner
,泛型不是Foo<,,>
,而是Foo`3
。
我正在根据一些输入类型生成代码,所以我肯定需要反转通过 System.Type 实例提供的索引/维度信息。
@O.R.Mapper:你们中的哪一个可以将其发布为答案,以便我接受吗?
@MarcGravell:你们中的哪一个可以将其发布为答案,以便我接受吗?
【参考方案1】:
注意:这并不能直接解决您的问题
这是预期的逆转行为吗?
但我觉得它增加了。
您可以使用GenerateCodeFromExpression
返回一个字符串,该字符串可用于生成为您生成类型的代码,例如使用此代码(由hvd 修改自this SO answer):
/// <summary>
/// <para>Returns a readable name for this type.</para>
/// <para>e.g. for type = typeof(IEnumerable<IComparable<int>>),</para>
/// <para>type.FriendlyName() returns System.Collections.Generic.IEnumerable<System.IComparable<int>></para>
/// <para>type.Name returns IEnumerable`1</para>
/// <para>type.FullName() returns System.Collections.Generic.IEnumerable`1[[System.IComparable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</para>
/// </summary>
public static string FriendlyName(this Type type)
string result;
using ( var codeDomProvider = CodeDomProvider.CreateProvider("C#") )
var typeReferenceExpression = new CodeTypeReferenceExpression(new CodeTypeReference(type));
using ( var writer = new StringWriter() )
codeDomProvider.GenerateCodeFromExpression(typeReferenceExpression, writer, new CodeGeneratorOptions());
result = writer.GetStringBuilder().ToString();
return result;
通过让codeDomProvider
处理字符串表示,您可以确定生成的内容将与您定义类型的方式相匹配。
FullName
的结果:
// returns "System.String[,,,][,,][,]"
typeof(string[,][, ,][, , ,]).FullName;
// returns "System.String[,][,,][,,,]"
typeof(string[, , ,][, ,][,]).FullName;
// returns "System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
typeof(List<int>).FullName;
FriendlyName
的结果
// returns "string[,][,,][,,,]"
typeof(string[,][, ,][, , ,]).FriendlyName();
// returns "string[,,,][,,][,]"
typeof(string[, , ,][, ,][,]).FriendlyName();
// returns "System.Collections.Generic.List<int>"
typeof(List<int>).FriendlyName();
【讨论】:
【参考方案2】:虽然Type.FullName
返回的值和 C# 类型标识符有时碰巧相同,但这并不能保证。请记住,Type.FullName
无论从哪种 CLI 语言调用它,无论是 C#、VB.NET、Oxygene 还是其他任何语言,都会返回相同的值。
对于多维和锯齿状数组,C# 语法按照它们稍后编写的顺序列出索引,而反射语法返回与数组的逻辑结构相匹配的内容。毕竟,(C#)string[,][,,][,,,]
是 string
类型的值,它是一个 4 维数组(即 string[,,,]
),它是一个 3 维数组(即 string[,,,][,,]
),它是一个 2维数组(即string[,,,][,,][,]
)。
您可能希望在分析类型时检查Type
类的属性,而不是依赖FullName
返回的反射语法名称。可以从那里检索number of dimensions 或generic arguments 等信息。
在构造类型时,您还可以使用MakeArrayType
或MakeGenericType
等方法在运行时创建复杂类型,而无需构造包含新类型成分的字符串。
Marc Gravell 指出了这个答案的部分内容——谢谢!
【讨论】:
以上是关于System.Type.FullName 的意外值的主要内容,如果未能解决你的问题,请参考以下文章