2012-07-30 9 views
20

Recientemente necesario para construir C# nombre específico (que siempre debe incluir mundial :: especificador) de un tipo arbitrario y han llegado al otro lado siguiente problema:valor inesperado de System.Type.FullName

// 1 - value: System.String[,,,][,,][,] 
string unexpectedFullName = typeof(string[,][,,][,,,]).FullName;  

// 2 - value: System.String[,][,,][,,,] 
string expectedFullName = Type.GetType("System.String[,][,,][,,,]").FullName; 

que estaba esperando ese valor devuelto sería el mismo en ambos casos. Sin embargo, por alguna razón, la parte relacionada con el conjunto del valor parece invertirse (caso 1). ¿Este comportamiento de reversión es esperado?

+6

me he encontrado esto antes; parece que mientras en C# declaras índices/dimensiones de matriz en el orden en el que lees, reflection devuelve un nombre de tipo que coincide con su estructura lógica. Y un (C#) 'string [,] [,,] [,,,]' es, después de todo, un valor de tipo 'string', de lo cual un array de 4 dimensiones (es decir' string [,,,] ') , de eso una matriz tridimensional (es decir 'cadena [,,,] [,,]') y de la misma una matriz bidimensional (es decir 'cadena [,,,] [,,] [,]'). –

+6

Todo lo que dijo ^^^^. La sintaxis de C# ([explicada en profundidad aquí] (http://blogs.msdn.com/b/ericlippert/archive/2009/08/17/arrays-of-arrays.aspx)) no es necesaria para coincidir con el nombre de reflexión convención. Entonces, si está tratando con la reflexión: use la denominación de reflexión. En otras noticias, los tipos anidados no son 'Outer.Inner' sino' Outer + Inner' en su lugar, y los genéricos no son 'Foo <,,>' sino 'Foo \' 3' en su lugar. –

+0

Estoy generando código basado en algunos tipos de entrada, así que definitivamente necesitaré revertir la información sobre los índices/dimensiones proporcionados a través de la instancia de System.Type. –

Respuesta

13

Si bien el valor devuelto por Type.FullName y el identificador de tipo C# a veces resultan ser los mismos, esto no está garantizado. Tenga en cuenta que Type.FullName devuelve el mismo valor independientemente del idioma de la CLI desde el que se llama, ya sea C#, VB.NET, Oxygene o cualquier otra cosa.

Para matrices multidimensionales y irregulares, la sintaxis de C# enumera los índices en el orden en que se escriben más adelante, mientras que la sintaxis de reflexión devuelve algo que coincide con la estructura lógica de la matriz. Y un (C#) string[,][,,][,,,] es, después de todo, un valor del tipo string, un conjunto tetradimensional (es decir, string[,,,]), un conjunto tridimensional (es decir, string[,,,][,,]) y, por lo tanto, un conjunto bidimensional (es decir, string[,,,][,,][,]).

En lugar de basarse en el nombre de sintaxis de reflexión devuelto por FullName, es posible que desee examinar las propiedades de la clase Type al analizar los tipos. La información como number of dimensions o generic arguments se puede recuperar desde allí.

Al construir tipos, también puede usar métodos como MakeArrayType o MakeGenericType para crear tipos complejos en tiempo de ejecución sin construir una cadena que contenga los ingredientes para los nuevos tipos.

Parte del contenido de esta respuesta fue señalado por Marc Gravell - ¡gracias!

2

Nota: Esto no se refiere directamente a su pregunta

es el comportamiento esperado esta inversión?

pero lo siento agrega a él.


Puede utilizar GenerateCodeFromExpression para devolver una cadena que podría ser utilizado para generar el código para generar el tipo para que, por ejemplo, utilizando el código (modificado de this SO answer por hvd):

/// <summary> 
/// <para>Returns a readable name for this type.</para> 
/// <para>e.g. for type = typeof(IEnumerable&lt;IComparable&lt;int&gt;&gt;),</para> 
/// <para>type.FriendlyName() returns System.Collections.Generic.IEnumerable&lt;System.IComparable&lt;int&gt;&gt;</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; 
} 

Al dejar codeDomProvider manejar la representación de cadena, puede estar seguro que lo que se generará coincidirá con la forma en que defina el Tipo.

Los resultados con 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; 

Los resultados con FriendlyName

// returns "string[,][,,][,,,]" 
typeof(string[,][, ,][, , ,]).FriendlyName(); 

// returns "string[,,,][,,][,]" 
typeof(string[, , ,][, ,][,]).FriendlyName(); 

// returns "System.Collections.Generic.List<int>" 
typeof(List<int>).FriendlyName();