Print full signature of a method from a MethodInfo
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)
Checkout the GetParameters() method on MethodBase. That will give you the info about the parameters including the name of the parameter. I don't believe a pre-existing method exists to print out the name but using the ParameterInfo[] to build that should be trivial.
How about this:
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();
}
Update 3/22/2018
I've rewritten the code, added a few tests, and uploaded it to GitHub
It's also available through nuget
Eltons.ReflectionKit
Answer
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.