Подтвердить что ты не робот

Печать полной сигнатуры метода из метода.

Существуют ли в .NET BCL какие-либо функциональные возможности для печати полной подписи метода во время выполнения (например, что вы увидите в Visual Studio ObjectBrowser - включая имена параметров) с использованием информации, доступной из MethodInfo?

Так, например, если вы посмотрите на String.Compare(), одна из перегрузок будет выглядеть так:

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

Обратите внимание на наличие полной подписи со всеми квалификаторами доступа и области действия, а также полного списка параметров, включая имена. Это то, что я ищу. Я мог бы написать свой собственный метод, но я бы предпочел использовать существующую реализацию, если это возможно.

4b9b3361

Ответ 1

К сожалению, я не верю, что есть встроенный метод, который бы это сделал. Лучше всего было бы создать свою собственную подпись, исследуя класс MethodInfo

EDIT: я просто сделал это

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

и вы получите

Void Main (System.String [])

Возможно, это не то, что вы ищете, но оно близко.

Как насчет этого

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

Это результат

Int32 Compare (String strA, Int32 indexA, String strB, Int32 indexB, Int32 длина, StringComparison comparisonType)

Ответ 2

Обновление от 22.03.2008

Я переписал код, добавил несколько тестов и загрузил его на GitHub

Ответ

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

    }
}

Это обрабатывает практически все, включая методы расширения. Начал с http://www.pcreview.co.uk/forums/getting-correct-method-signature-t3660896.html.

Я использовал его в тандуме с шаблоном T4 для генерации перегрузок для всех методов расширения Queryable и Enumerable Linq.

Ответ 3

Оформить метод GetParameters() на базе MethodBase. Это даст вам информацию о параметрах, включая имя параметра. Я не верю, что существует существующий метод для печати имени, но с использованием ParameterInfo [] для сборки, который должен быть тривиальным.

Как насчет этого:

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

Ответ 4

Если метод имеет параметр, ParameterInfo.Member.ToString() выведет то, что вы хотите. Если нет, то создать подпись довольно легко. Этот метод вернет то, что вы хотите:

public string PrintSignature(MethodInfo methodInfo)
{
    ParameterInfo[] parameters = methodInfo.GetParameters();
    return parameters.Length > 0 ? parameters[0].Member.ToString() : $"{methodInfo.ReturnType.ToString()} {methodInfo.Name}()";
}

Если вы также хотите получить квалификаторы доступа:

public string GetSignatureSansModifiers(MethodInfo methodInfo)
{
    ParameterInfo[] parameters = methodInfo.GetParameters();
    return parameters.Length > 0 ? parameters[0].Member.ToString() : $"{methodInfo.ReturnType.ToString()} {methodInfo.Name}()";
}

public string PrintSignature(MethodInfo methodInfo)
{
    StringBuilder sb = new StringBuilder();

    if (methodInfo.IsPrivate)
        sb.Append("private ");
    else if (methodInfo.IsPublic)
        sb.Append("public ");
    if (methodInfo.IsAbstract)
        sb.Append("abstract ");
    if (methodInfo.IsStatic)
        sb.Append("static ");
    if (methodInfo.IsVirtual)
        sb.Append("virtual ");
    sb.Append(GetSignatureSansModifiers(methodInfo));
    return sb.ToString();
}