2008-12-30 13 views
25

Estoy trabajando en la generación de código y me encontré con un problema con los genéricos. Aquí hay una versión "simplificada" de lo que me está causando problemas.¿Cómo puedo obtener la definición de texto correcta de un tipo genérico utilizando la reflexión?

Dictionary<string, DateTime> dictionary = new Dictionary<string, DateTime>(); 
string text = dictionary.GetType().FullName; 

Con el código anterior fragmento de código del valor de text es el siguiente: (. Los saltos de línea añaden para facilitar la lectura)

System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.DateTime, mscorlib, 
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] 

¿Hay una manera de obtener el nombre del tipo (type) en un formato diferente sin analizar la cadena anterior? Yo deseo el siguiente resultado para text:

System.Collections.Generic.Dictionary<System.String, System.DateTime> 
+2

Tenga en cuenta que si se quita '' .FullName' y utilizar .ToString() 'en lugar, se obtiene el" text "' 'System.Collections.Generic.Dictionary'2 [System.String, System.DateTime]' 'que es más legible y está más cerca de lo que desea. –

Respuesta

27

No hay manera integrada para obtener esta representación en el .Net Framework. A saber, porque no hay forma de hacerlo correcto. Hay un buen número de construcciones que no son representables en la sintaxis de estilo C#. Por ejemplo, "<> foo" es un nombre de tipo válido en IL pero no se puede representar en C#.

Sin embargo, si está buscando una solución bastante buena, puede implementarla a mano con bastante rapidez. La siguiente solución funcionará para la mayoría de las situaciones. No va a manejar

  1. tipos anidados
  2. ilegales C# Nombres
  3. par de otros escenarios

Ejemplo:

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

¡Por encima y más allá! Esto funciona perfectamente! ¡¡Gracias!! –

+0

si tiene la oportunidad, edite su respuesta e incluya "cadena estática GetFriendlyTypeName (Tipo de tipo) {if (tipo.Positivo genérico) {return type.Name;}" en el bloque de código :) –

+0

@Jamey, hecho. Esto es realmente bastante extraño. El bloque de código no agregaría la primera línea hasta que agregue una línea que no sea de código entre la lista ordenada y el inicio del bloque. – JaredPar

0

no creo .NET se ha incorporado en cualquier cosa que pudiera hacer esto, por lo que tendrá que hacerlo usted mismo. Creo que las clases de reflexión proporcionan información suficiente para reconstruir el nombre del tipo en esta forma.

+0

He intentado este camino ¿puede elaborar sobre la solución? No he encontrado propiedades o colecciones que me brinden esta información que pueda usar para reconstruir la declaración. –

0

Creo que se puede pasar

System.String, mscorlib, versión = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089

en Type.Parse(). Ese es un nombre de tipo completamente calificado, creo.

+0

No es necesario. El Dictionary.GetType() original ya contiene una colección de parámetros de tipo a los que puede acceder directamente. No es necesario analizar para obtener el mismo resultado. –

2
string text = dictionary.ToString(); 

proporciona casi lo que usted está pidiendo:

System.Collections.Generic.Dictionary`2[System.String,System.DateTime] 
+0

Sin embargo, esta no es una solución genérica. Cualquier tipo que use .ToString() romperá esta solución – JaredPar

+0

@JaredPar Esto se resuelve usando 'dictionary.GetType(). ToString()' en su lugar. –

4

Esta tarde estaba jugando un poco con los métodos de extensión e intenté encontrar una respuesta para tu pregunta. Este es el resultado: es un código sin garantía. ;-)

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

Gracias! Esta solución también funciona. –

19

Una alternativa buena y limpia, gracias a @LukeH's comment, es

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); 
    } 
} 
+3

mucho mejor que marcado como respuesta (las subclases de las clases genéricas se muestran correctamente) – FLCL

+2

¿Tiene alguna repercusión en el rendimiento? –

Cuestiones relacionadas