代码之家  ›  专栏  ›  技术社区  ›  LBushkin

打印MethodInfo中方法的完整签名

  •  28
  • LBushkin  · 技术社区  · 15 年前

    .NET中是否有任何现有功能 BCL 要在运行时使用来自MethodInfo的信息打印方法的完整签名(如在Visual Studio ObjectBrowser中看到的内容,包括参数名)?

    例如,如果查找string.compare(),其中一个重载将打印为:

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

    注意完整签名的存在,包括所有访问和作用域限定符,以及包括名称在内的参数的完整列表。这就是我要找的。我可以编写自己的方法,但如果可能的话,我宁愿使用现有的实现。

    3 回复  |  直到 7 年前
        1
  •  26
  •   Stan R.    15 年前

    不幸的是,我不相信有一个内置的方法可以做到这一点。最好是通过调查MethodInfo类来创建自己的签名。

    编辑:我刚刚做的

     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比较(字符串stra,Int32 索引a,字符串strb,int32 indexb,int32 长度,字符串比较 比较型)

        2
  •  26
  •   Kelly Elton    7 年前

    更新日期:2018年3月22日

    我重写了代码,添加了一些测试,并且 uploaded it to 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 .

    我在tandum中使用它和一个t4模板来为所有 Queryable Enumerable LINQ扩展方法。

        3
  •  0
  •   Niklas    10 年前

    签出methodBase上的getParameters()方法。这将提供有关参数的信息,包括参数的名称。我不认为存在一个预先存在的方法来打印出名称,但是使用参数信息[]来构建它应该是很简单的。

    这个怎么样?

    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();
    }
    
    推荐文章