Is there any existing functionality in the .NET BCL to print the full signature of a method at runtime (like what you'd see in the Visual Studio ObjectBrowser - including parameter names) using information available from MethodInfo?
So for example, if you look up String.Compare() one of the overloads would print as:
public static int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignoreCase, System.Globalization.CultureInfo culture)
Note the presence of the complete signature with all access and scope qualifiers as well as a complete list of parameters including names. This is what I'm looking for. I could write my own method, but I would rather use an existing implementation if possible.
I've rewritten the code, added a few tests, and uploaded it to GitHub
It's also available through nuget
Eltons.ReflectionKit
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();
}
}
}
This handles practically everything, including extension methods. Got a head start from http://www.pcreview.co.uk/forums/getting-correct-method-signature-t3660896.html.
I used it in tandum with a T4 template to generate overloads for all the Queryable
and Enumerable
Linq extension methods.
Unfortunately I don't believe there is a built in method that would do that. Your best be would be to create your own signature by investigating the MethodInfo class
EDIT: I just did this
MethodBase mi = MethodInfo.GetCurrentMethod();
mi.ToString();
and you get
Void Main(System.String[])
This might not be what you're looking for, but it's close.
How about this
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());
}
This is the result
Int32 Compare(String strA,Int32 indexA,String strB,Int32 indexB,Int32 length,StringComparison comparisonType)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With