2010-12-06 12 views
15

J'utilise la réflexion pour imprimer une signature de méthode, par ex.Comment puis-je obtenir le nom primitif d'un type en C#?

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

Cela fonctionne assez bien, mais il imprime le type de primitives comme "System.String" au lieu de "string" et "System.Nullable`1 [System.Int32]" au lieu de "int?" . Existe-t-il un moyen d'obtenir le nom du paramètre tel qu'il apparaît dans le code, par ex.

public Example(string p1, int? p2) 

impressions

p1: string 
p2: int? 

au lieu de

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

Répondre

24

EDIT: Je moitié mal dans la réponse ci-dessous.

Jetez un oeil à CSharpCodeProvider.GetTypeOutput. Exemple de code:

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 
    } 
} 

Cependant, cette n'a pas traduit Nullable<T> en T? - et je ne peux pas trouver toutes les options qui en ferait le faire, même si cela ne signifie pas une telle option ne existent :)


Rien dans le framework ne supporte cela - après tout, ce sont des noms spécifiques à C#.

(Notez que stringn'est pas un primitive type, en passant.)

Vous devrez le faire en repérant Nullable`1 vous et une carte du nom complet du cadre à chaque alias.

+0

Vous ne pouvez pas attendre votre mise à jour :) – basarat

+0

'CSharpCodeProvider.GetTypeOutput' ne change pas' System.String' en 'string' cependant. –

+0

@Mark: Hmm ... il fait sur ma boîte ... –

1

n ° string est juste une représentation de System.String - string ne veut vraiment rien dire dans les coulisses.

Par ailleurs, pour obtenir passé System.Nullable'1[System.Int32], vous pouvez utiliser Nullable.GetUnderlyingType(type);

0

Ce sont les noms réels des types en question. string et int? ne sont que des alias C# pour ces types. Vous devez faire la cartographie vous-même.

4

Cette question a deux réponses intéressantes. Le accepted one de Jon Skeet dit à peu près ce qu'il a déjà dit.

EDIT Jon a mis à jour sa réponse si son à peu près la même que la mienne est maintenant. (Mais bien sûr, 20 secondes plus tôt)

Mais Luke H donne aussi this answer ce que je pensais être une utilisation plutôt géniale du 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

Voici ce que j'ai trouvé après ~ 5 minutes de piratage.Par exemple:

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

renverra 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

Que diriez-vous des tableaux? Un tableau bidimensionnel de int devrait être "int [,]" ou "System.Int32 [,]", ou quoi? –

+0

@Eric: Oups, oublié A propos des types de tableaux J'ai mis à jour la méthode pour les gérer – cdhowie

+0

Votre code est maintenant faux pour les types de tableaux irréguliers Rappelez-vous, un int [,] [] est un tableau bidimensionnel de tableaux unidimensionnels, pas un unidimensionnel –

1

Pas le plus beau code dans le monde, mais ce que je fini par faire: (bâtiment sur le code 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; 
} 
0

Une autre option, en fonction des autres réponses ici.

Caractéristiques:

  • Convertir chaîne à cordes et à Int32 int etc
  • Traiter Nullable comme int? etc
  • System.DateTime être Suppress DateTime
  • Tous les autres types sont écrits en pleine

Il traite des cas simples je avais besoin, pas sûr si elle traitera des types complexes et ..

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