2010-12-06 10 views
15

Ich verwende Reflexion, um eine Methodensignatur, z.Wie kann ich den primitiven Namen eines Typs in C# bekommen?

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

Das funktioniert ziemlich gut, aber es gibt die Art von Primitiven als „System.String“ out statt „String“ und „System.Nullable`1 [System.Int32]“ anstelle von „int?“ . Gibt es eine Möglichkeit, den Namen des Parameters so zu erhalten, wie er im Code aussieht, z.

public Example(string p1, int? p2) 

druckt

p1: string 
p2: int? 

statt

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

Antwort

24

EDIT: Ich war unten in der Antwort Hälfte falsch.

Werfen Sie einen Blick auf CSharpCodeProvider.GetTypeOutput. Beispielcode:

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

Doch diese nicht übersetzen Nullable<T> in T? - und ich kann keine Optionen finden, die sie so tun würde, aber das ist nicht eine solche Option bedeutet nicht exists :)

Es gibt nichts im Rahmen, um dies zu unterstützen - schließlich sind sie C# -spezifische Namen.

(Beachten Sie, dass stringnicht ein primitive type ist, übrigens.)

Sie werden es von Nullable`1 selbst Spek zu tun haben, und eine Karte aus dem vollen Rahmen Namen jedes Alias ​​haben.

+0

Ich kann kaum auf dein Update warten :) – basarat

+0

'CSharpCodeProvider.GetTypeOutput' ändert' System.String' nicht in 'string' obwohl. –

+0

@Mark: Hmm ... tut es auf meiner Box ... –

1

Nr. string ist nur eine Darstellung von System.String - string bedeutet nicht wirklich etwas hinter den Kulissen.

By the way, erhalten Vergangenheit System.Nullable'1[System.Int32] Sie Nullable.GetUnderlyingType(type);

0

Das sind die tatsächlichen Namen der Arten in Frage verwenden können. string und int? sind nur C# Aliase für diese Typen. Sie müssen das Mapping selbst durchführen.

4

Diese question hat zwei interessante Antworten. Die accepted one von Jon Skeet sagt ziemlich viel, was er schon gesagt hat.

EDIT Jon aktualisiert seine Antwort so seine ziemlich das gleiche wie ich jetzt. (Aber natürlich 20 Sekunden früher)

Aber Luke H gibt auch this answer, die ich dachte, war ziemlich tolle Verwendung des 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

Hier ist, was ich nach ~ 5 Minuten Hacking kam.Zum Beispiel:

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

wird System.Collections.Generic.IDictionary<string, int?> zurückgeben.

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

Was ist mit Arrays? Sollte ein zweidimensionales Array von int "int [,]" oder "System.Int32 [,]", oder was? –

+0

@Eric: Ups, vergessen Über Array-Typen Ich habe die Methode aktualisiert, um sie zu behandeln – cdhowie

+0

Ihr Code ist jetzt falsch für zackige Array-Typen Beachten Sie, dass ein int [,] [] ein zweidimensionales Array eindimensionaler Arrays ist, nicht eindimensional Array von zweidimensionalen Arrays –

1

Nicht der schönste Code in der Welt, aber das ist, was ich tun endete: (aufbauend auf Cornard Code)

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

Eine weitere Möglichkeit, auf der Grundlage der anderen Antworten hier.

Features:

  • Convert String zu String und Int32 zu etc int
  • Deal mit Nullable als int? etc
  • Suppress System.DateTime
  • Alle anderen Typen geschrieben Es befasst sich mit den einfachen Fällen in voller

Datetime zu sein, die ich brauchte, nicht sicher, ob es gut komplexe Typen behandelt ..

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