¿Cómo puedo obtener el nombre primitivo de un tipo en C #?

Estoy usando la reflexión para imprimir una firma de método, por ejemplo

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

Esto funciona bastante bien, pero imprime el tipo de primitivas como “System.String” en lugar de “string” 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, por ejemplo,

 public Example(string p1, int? p2) 

huellas dactilares

 p1: string p2: int? 

en lugar de

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

EDITAR: Estaba medio equivocado en la respuesta a continuación.

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

 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 convierte Nullable en T? – y no puedo encontrar ninguna opción que lo haga, aunque eso no significa que tal opción no exista 🙂


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

(Tenga en cuenta que la string no es un tipo primitivo , por cierto).

Tendrás que hacerlo al detectar Nullable`1 tú mismo, y tener un mapa del nombre completo del framework para cada alias.

Esta pregunta tiene dos respuestas interesantes. El aceptado de Jon Skeet casi dice lo que dijo.

EDITAR Jon actualizó su respuesta por lo que es más o menos lo mismo que el mío ahora. (Pero por supuesto 20 segundos antes)

Pero Luke H también da esta respuesta que pensé que era un uso bastante increíble 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 

No. string es solo una representación de System.Stringstring realmente no significa nada detrás de escena.

Por cierto, para pasar System.Nullable'1[System.Int32] , puede usar Nullable.GetUnderlyingType(type);

No es el código más hermoso del mundo, pero esto es lo que terminé haciendo: (basándose en el código de 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; } 

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

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

caracteristicas:

  • Convertir cadena a cadena e Int32 a int, etc.
  • ¿Tratar con Nullable como int? etc
  • Suprima System.DateTime para ser DateTime
  • Todos los demás tipos están escritos en su totalidad

Se trata de los casos simples que necesitaba, no estoy seguro si manejará bien los tipos complejos …

  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.",""); } 

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

 CSharpAmbiance.GetTypeName(typeof(IDictionary)) 

devolverá System.Collections.Generic.IDictionary .

 public static class CSharpAmbiance { private static Dictionary aliases = new Dictionary(); 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(); 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; } }