2010-12-06 13 views
15

Uso el reflejo para imprimir una firma de método, p.¿Cómo puedo obtener el nombre primitivo de un tipo en C#?

foreach (var pi in mi.GetParameters()) { 
    Console.WriteLine(pi.Name + ": " + pi.ParameterType.ToString()); 
} 

Esto funciona bastante bien, pero se imprime el tipo de primitivas como "System.String" en lugar de "cadena" y "System.Nullable`1 [System.Int32]" en lugar de "int?" . ¿Hay alguna manera de obtener el nombre del parámetro como se ve en el código, p.

public Example(string p1, int? p2) 

impresiones

p1: string 
p2: int? 

en lugar de

p1: System.String 
p2: System.Nullable`1[System.Int32] 

Respuesta

24

EDIT: yo estaba medio mal en la respuesta a continuación.

Eche un vistazo a CSharpCodeProvider.GetTypeOutput. Código de ejemplo:

using Microsoft.CSharp; 
using System; 
using System.CodeDom; 

class Test 
{ 
    static void Main() 
    { 
     var compiler = new CSharpCodeProvider(); 
     // Just to prove a point... 
     var type = new CodeTypeReference(typeof(Int32)); 
     Console.WriteLine(compiler.GetTypeOutput(type)); // Prints int 
    } 
} 

Sin embargo, esto no traducen en Nullable<T>T? - y no puedo encontrar ninguna opción que harían lo haga, aunque eso no significa que esta opción no hace existe :)


No hay nada en el marco para soportar esto - después de todo, son nombres específicos de C#.

(Tenga en cuenta que no es string un primitive type, por cierto.)

Vas a tener que hacerlo mediante la detección de Nullable`1 mismo, y tener un mapa a partir del nombre completo framework para cada alias.

+0

No puedo esperar a su actualización :) – basarat

+0

'CSharpCodeProvider.GetTypeOutput' no cambia' System.String' por 'string' embargo. –

+0

@Mark: Hmm ... lo hace en mi caja ... –

1

es una representación de System.String - string realmente no significa nada detrás de escena.

Por cierto, para conseguir más allá System.Nullable'1[System.Int32], puede utilizar Nullable.GetUnderlyingType(type);

0

Esos son los nombres reales de los tipos en cuestión. string y int? son solo alias de C# para esos tipos. Tienes que hacer el mapeo tú mismo.

4

Esta question tiene dos respuestas interesantes. El accepted one de Jon Skeet prácticamente dice lo que dijo.

EDITAR Jon actualiza su respuesta por lo que su más o menos la misma que la mía es ahora. (Pero, por supuesto, 20 segundos antes)

Pero Luke H también da this answer que pensé que era un uso bastante impresionante del CodeDOM.

Type t = column.DataType; // Int64 

StringBuilder sb = new StringBuilder(); 
using (StringWriter sw = new StringWriter(sb)) 
{ 
    var expr = new CodeTypeReferenceExpression(t); 

    var prov = new CSharpCodeProvider(); 
    prov.GenerateCodeFromExpression(expr, sw, new CodeGeneratorOptions()); 
} 

Console.WriteLine(sb.ToString()); // long 
-3

Esto es lo que se me ocurrió después de unos 5 minutos de pirateo.Por ejemplo:

CSharpAmbiance.GetTypeName(typeof(IDictionary<string,int?>)) 

devolverá System.Collections.Generic.IDictionary<string, int?>.

public static class CSharpAmbiance 
{ 
    private static Dictionary<Type, string> aliases = 
     new Dictionary<Type, string>(); 

    static CSharpAmbiance() 
    { 
     aliases[typeof(byte)] = "byte"; 
     aliases[typeof(sbyte)] = "sbyte"; 
     aliases[typeof(short)] = "short"; 
     aliases[typeof(ushort)] = "ushort"; 
     aliases[typeof(int)] = "int"; 
     aliases[typeof(uint)] = "uint"; 
     aliases[typeof(long)] = "long"; 
     aliases[typeof(ulong)] = "ulong"; 
     aliases[typeof(char)] = "char"; 

     aliases[typeof(float)] = "float"; 
     aliases[typeof(double)] = "double"; 

     aliases[typeof(decimal)] = "decimal"; 

     aliases[typeof(bool)] = "bool"; 

     aliases[typeof(object)] = "object"; 
     aliases[typeof(string)] = "string"; 
    } 

    private static string RemoveGenericNamePart(string name) 
    { 
     int backtick = name.IndexOf('`'); 

     if (backtick != -1) 
      name = name.Substring(0, backtick); 

     return name; 
    } 

    public static string GetTypeName(Type type) 
    { 
     if (type == null) 
      throw new ArgumentNullException("type"); 

     string keyword; 
     if (aliases.TryGetValue(type, out keyword)) 
      return keyword; 

     if (type.IsArray) { 
      var sb = new StringBuilder(); 

      var ranks = new Queue<int>(); 
      do { 
       ranks.Enqueue(type.GetArrayRank() - 1); 
       type = type.GetElementType(); 
      } while (type.IsArray); 

      sb.Append(GetTypeName(type)); 

      while (ranks.Count != 0) { 
       sb.Append('['); 

       int rank = ranks.Dequeue(); 
       for (int i = 0; i < rank; i++) 
        sb.Append(','); 

       sb.Append(']'); 
      } 

      return sb.ToString(); 
     } 

     if (type.IsGenericTypeDefinition) { 
      var sb = new StringBuilder(); 

      sb.Append(RemoveGenericNamePart(type.FullName)); 
      sb.Append('<'); 

      var args = type.GetGenericArguments().Length - 1; 
      for (int i = 0; i < args; i++) 
       sb.Append(','); 

      sb.Append('>'); 

      return sb.ToString(); 
     } 

     if (type.IsGenericType) { 
      if (type.GetGenericTypeDefinition() == typeof(Nullable<>)) 
       return GetTypeName(type.GetGenericArguments()[0]) + "?"; 

      var sb = new StringBuilder(); 

      sb.Append(RemoveGenericNamePart(type.FullName)); 
      sb.Append('<'); 

      var args = type.GetGenericArguments(); 
      for (int i = 0; i < args.Length; i++) { 
       if (i != 0) 
        sb.Append(", "); 

       sb.Append(GetTypeName(args[i])); 
      } 

      sb.Append('>'); 

      return sb.ToString(); 
     } 

     return type.FullName; 
    } 
} 
+0

¿Qué pasa con las matrices? ¿Debe una matriz bidimensional de int ser "int [,]" o "System.Int32 [,]", o qué? –

+0

@Eric: Oops, se olvidó sobre los tipos de arreglos. He actualizado el método para manejarlos. – cdhowie

+0

Su código ahora es incorrecto para los tipos de arreglos irregulares. Recuerde, un int [,] [] es un arreglo bidimensional de matrices unidimensionales, no unidimensionales array de matrices bidimensionales. –

1

No es el código más bella del mundo, pero esto es lo que terminé haciendo: (basándose en el código del Cornard)

public static string CSharpName(this Type type) 
{ 
    if (!type.FullName.StartsWith("System")) 
     return type.Name; 
    var compiler = new CSharpCodeProvider(); 
    var t = new CodeTypeReference(type); 
    var output = compiler.GetTypeOutput(t); 
    output = output.Replace("System.",""); 
    if (output.Contains("Nullable<")) 
     output = output.Replace("Nullable","").Replace(">","").Replace("<","") + "?"; 
    return output; 
} 
0

Otra opción, en función de las otras respuestas aquí.

Características: Cadena

  • Convertir a cuerda y Int32 a int etc
  • acuerdo con anulable como int? etc
  • reprimir System.DateTime sea DateTime
  • Todos los demás tipos están escritos en su totalidad

Se trata de los casos simples que necesitaba, no está seguro de si va a manejar tipos de complejos así ..

 Type type = /* Get a type reference somehow */ 
     if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 
     { 
      return compiler.GetTypeOutput(new CodeTypeReference(type.GetGenericArguments()[0])).Replace("System.","") + "?"; 
     } 
     else 
     { 
      return compiler.GetTypeOutput(new CodeTypeReference(type)).Replace("System.",""); 
     }  
Cuestiones relacionadas