2009-08-21 6 views
25

Existe-t-il une fonctionnalité existante dans .NET BCL pour imprimer la signature complète d'une méthode lors de l'exécution (comme ce que vous verriez dans Visual Studio ObjectBrowser - y compris les noms de paramètres) en utilisant information disponible de MethodInfo?Impression de la signature complète d'une méthode à partir d'un MethodInfo

Ainsi, par exemple, si vous regardez String.Compare() l'une des surcharges imprimerait comme:

public static int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignoreCase, System.Globalization.CultureInfo culture) 

Notez la présence de la signature avec tous les qualificatifs d'accès et la portée ainsi qu'une complète liste des paramètres incluant les noms. C'est ce que je cherche. Je pourrais écrire ma propre méthode, mais je préférerais utiliser une implémentation existante si possible.

Répondre

24

Malheureusement, je ne crois pas qu'il existe une méthode intégrée qui ferait cela. Votre meilleure façon serait de créer votre propre signature en enquêtant sur la classe MethodInfo

EDIT: Je viens de faire ce

MethodBase mi = MethodInfo.GetCurrentMethod(); 
mi.ToString(); 

et vous obtenez

Void Main (System.String [ ])

Cela peut ne pas être ce que vous cherchez, mais c'est proche.

Que diriez-vous de cette

public static class MethodInfoExtension 
     { 
      public static string MethodSignature(this MethodInfo mi) 
      { 
       String[] param = mi.GetParameters() 
           .Select(p => String.Format("{0} {1}",p.ParameterType.Name,p.Name)) 
           .ToArray(); 


      string signature = String.Format("{0} {1}({2})", mi.ReturnType.Name, mi.Name, String.Join(",", param)); 

      return signature; 
     } 
    } 

    var methods = typeof(string).GetMethods().Where(x => x.Name.Equals("Compare")); 

    foreach(MethodInfo item in methods) 
    { 
     Console.WriteLine(item.MethodSignature()); 
    } 

Ceci est le résultat

Int32 Comparer (String Stra Int32 indexA, String strB, Int32 indexB, Int32 longueur , StringComparison comparisonType)

+0

Merci. Malheureusement, mon cas d'utilisation nécessite les noms de paramètres de la méthode, que MethodInfo.ToString() n'émet pas. – LBushkin

+1

oui il n'affiche pas non plus d'attributs de méthode. –

0

Extrayez la méthode GetParameters() sur MethodBase. Cela vous donnera l'information sur les paramètres, y compris le nom du paramètre. Je ne crois pas qu'une méthode préexistante existe pour imprimer le nom, mais en utilisant le ParameterInfo [] pour construire cela devrait être trivial.

Que diriez-vous ceci:

public string GetSignature(MethodInfo mi) 
{ 
    if(mi == null) 
    return ""; 
    StringBuilder sb = new StringBuilder(); 

    if(mi.IsPrivate) 
    sb.Append("private "); 
    else if(mi.IsPublic) 
    sb.Append("public "); 
    if(mi.IsAbstract) 
    sb.Append("abstract "); 
    if(mi.IsStatic) 
    sb.Append("static "); 
    if(mi.IsVirtual) 
    sb.Append("virtual "); 

    sb.Append(mi.ReturnType.Name + " "); 

    sb.Append(mi.Name + "("); 

    String[] param = mi.GetParameters() 
    .Select(p => String.Format(
       "{0} {1}",p.ParameterType.Name,p.Name)) 
          .ToArray(); 


    sb.Append(String.Join(", ",param)); 

    sb.Append(")"); 

    return sb.ToString(); 
} 
24
using System.Text; 

namespace System.Reflection 
{ 
    public static class MethodInfoExtensions 
    { 
     /// <summary> 
     /// Return the method signature as a string. 
     /// </summary> 
     /// <param name="method">The Method</param> 
     /// <param name="callable">Return as an callable string(public void a(string b) would return a(b))</param> 
     /// <returns>Method signature</returns> 
     public static string GetSignature(this MethodInfo method, bool callable = false) 
     { 
      var firstParam = true; 
      var sigBuilder = new StringBuilder(); 
      if (callable == false) 
      { 
       if (method.IsPublic) 
        sigBuilder.Append("public "); 
       else if (method.IsPrivate) 
        sigBuilder.Append("private "); 
       else if (method.IsAssembly) 
        sigBuilder.Append("internal "); 
       if (method.IsFamily) 
        sigBuilder.Append("protected "); 
       if (method.IsStatic) 
        sigBuilder.Append("static "); 
       sigBuilder.Append(TypeName(method.ReturnType)); 
       sigBuilder.Append(' '); 
      } 
      sigBuilder.Append(method.Name); 

      // Add method generics 
      if(method.IsGenericMethod) 
      { 
       sigBuilder.Append("<"); 
       foreach(var g in method.GetGenericArguments()) 
       { 
        if (firstParam) 
         firstParam = false; 
        else 
         sigBuilder.Append(", "); 
        sigBuilder.Append(TypeName(g)); 
       } 
       sigBuilder.Append(">"); 
      } 
      sigBuilder.Append("("); 
      firstParam = true; 
      var secondParam = false; 
      foreach (var param in method.GetParameters()) 
      { 
       if (firstParam) 
       { 
        firstParam = false; 
        if (method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false)) 
        { 
         if (callable) 
         { 
          secondParam = true; 
          continue; 
         } 
         sigBuilder.Append("this "); 
        } 
       } 
       else if (secondParam == true) 
        secondParam = false; 
       else 
        sigBuilder.Append(", "); 
       if (param.ParameterType.IsByRef) 
        sigBuilder.Append("ref "); 
       else if (param.IsOut) 
        sigBuilder.Append("out "); 
       if (!callable) 
       { 
        sigBuilder.Append(TypeName(param.ParameterType)); 
        sigBuilder.Append(' '); 
       } 
       sigBuilder.Append(param.Name); 
      } 
      sigBuilder.Append(")"); 
      return sigBuilder.ToString(); 
     } 

     /// <summary> 
     /// Get full type name with full namespace names 
     /// </summary> 
     /// <param name="type">Type. May be generic or nullable</param> 
     /// <returns>Full type name, fully qualified namespaces</returns> 
     public static string TypeName(Type type) 
     { 
      var nullableType = Nullable.GetUnderlyingType(type); 
      if (nullableType != null) 
       return nullableType.Name + "?"; 

      if (!(type.IsGenericType && type.Name.Contains('`'))) 
       switch (type.Name) 
       { 
        case "String": return "string"; 
        case "Int32": return "int"; 
        case "Decimal": return "decimal"; 
        case "Object": return "object"; 
        case "Void": return "void"; 
        default: 
         { 
          return string.IsNullOrWhiteSpace(type.FullName) ? type.Name : type.FullName; 
         } 
       } 

      var sb = new StringBuilder(type.Name.Substring(0, 
      type.Name.IndexOf('`')) 
      ); 
      sb.Append('<'); 
      var first = true; 
      foreach (var t in type.GetGenericArguments()) 
      { 
       if (!first) 
        sb.Append(','); 
       sb.Append(TypeName(t)); 
       first = false; 
      } 
      sb.Append('>'); 
      return sb.ToString(); 
     } 

    } 
} 

Cette poignées pratiquement tout, y compris les méthodes d'extension. Vous avez une longueur d'avance de http://www.pcreview.co.uk/forums/getting-correct-method-signature-t3660896.html. Je l'ai utilisé dans tandum avec un modèle T4 pour générer des surcharges pour toutes les méthodes d'extension Linq Queryable et Enumerable.

+10

Merci pour cela ... m'a sauvé beaucoup de temps. Je l'ai construit un peu plus pour gérer les tableaux de paramètres, les paramètres optionnels et les contraintes génériques, ainsi que les propriétés. Toujours pas complet à 100% mais je pensais que je le passerais. https://gist.github.com/4476307 –

+1

@jametre Nice, je l'ai fourchu, je vais devoir jouer avec. –

+1

merci, c'est le travail pour les méthodes Generik et les paramètres génériques aussi –

Questions connexes