2009-08-21 13 views
25

¿Existe alguna funcionalidad en .NET BCL para imprimir la firma completa de un método en tiempo de ejecución (como lo que vería en el Visual Studio ObjectBrowser, incluidos los nombres de los parámetros) usando información disponible de MethodInfo?Imprimir la firma completa de un método de un MethodInfo

Así por ejemplo, si miras hacia arriba String.Compare() una de las sobrecargas imprimiría como:

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

nota la presencia de la firma completa con todos los calificadores de acceso y alcance, así como una completa lista de parámetros, incluidos los nombres. Esto es lo que estoy buscando. Podría escribir mi propio método, pero preferiría usar una implementación existente si fuera posible.

Respuesta

24

Desafortunadamente, no creo que haya un método incorporado que pueda hacer eso. Su mejor de los casos sería la creación de su propia firma mediante la investigación de la clase MethodInfo

EDIT: acabo de hacer esta

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

y se obtiene

void main (System.String [ ])

Esto podría no ser lo que estás buscando, pero está cerca.

¿Qué tal esto

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()); 
    } 

Este es el resultado

Int32 Comparar (String Stra, Int32 indiceA, Cadena strB, Int32 indiceB, Int32 longitud, StringComparison comparisonType)

+0

Gracias. Desafortunadamente, mi caso de uso requiere los nombres de los parámetros para el método, que MethodInfo.ToString() no emite. – LBushkin

+1

sí, también no muestra los atributos del método. –

0

Verifica el método GetParameters() en MethodBase. Eso le dará la información sobre los parámetros, incluido el nombre del parámetro. No creo que exista un método preexistente para imprimir el nombre pero usando ParameterInfo [] para compilar que debería ser trivial.

¿Qué tal esto:

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(); 
     } 

    } 
} 

Este se encarga de prácticamente todo, incluyendo los métodos de extensión. Tengo una ventaja desde http://www.pcreview.co.uk/forums/getting-correct-method-signature-t3660896.html.

Lo usé en tandum con una plantilla T4 para generar sobrecargas para todos los métodos de extensión Queryable y Enumerable Linq.

+10

Gracias por esto ... me ha ahorrado mucho tiempo. Lo construí un poco más para manejar matrices param, parámetros opcionales y restricciones genéricas, así como propiedades. Todavía no está completo al 100%, pero pensé que lo transmitiría. https://gist.github.com/4476307 –

+1

@jamietre Bien, lo bifurqué, tendré que jugar con eso. –

+1

gracias, eso funciona para los métodos de Generik y los parámetros genéricos también –

Cuestiones relacionadas