Get method signature display in C#

I once wrote a lightweight RESTful service to expose API based on method signature, and came across an idea to display the full method signature in the API document. The code is simple, but often hard to cover all the cases. Here is a summary of the “full” version. Comments welcomed if I missed anything.

public static string GetMethodSignature(this MethodInfo method, bool withNamespace = false)
{
    StringBuilder sb = new StringBuilder();

    // Access level
    if (method.IsPublic)
    {
        sb.Append("public ");
    }
    else if (method.IsPrivate)
    {
        sb.Append("private ");
    }
    else if (method.IsFamily)
    {
        sb.Append("protected ");
    }
    else if (method.IsAssembly)
    {
        sb.Append("internal ");
    }
    else if (method.IsFamilyOrAssembly)
    {
        sb.Append("protected internal ");
    }

    // Member or static
    if (method.IsStatic)
        sb.Append("static ");

    // Abstract or virtual
    if (method.IsAbstract)
    {
        sb.Append("abstract ");
    }
    else if (method.IsVirtual)
    {
        sb.Append("virtual ");
    }

    // Return type
    sb.Append(method.ReturnType.GetDisplayName(withNamespace) + " ");

    // Method name
    sb.Append(method.Name);

    // Generic method arguments
    if (method.IsGenericMethod)
    {
        sb.Append("<");
        sb.Append(string.Join(", ", method.GetGenericArguments()
            .Select(item => item.GetDisplayName(withNamespace))));
        sb.Append(">");
    }

    // Parameters
    sb.Append("(");
    sb.Append(string.Join(", ", method.GetParameters()
        .Select(item => item.GetDisplayName(withNamespace))));
    sb.Append(")");

    return sb.ToString();
}

The above method requires several supporting extension methods.

public static string GetDisplayName(this Type type, bool withNamespace = false)
{
    StringBuilder sb = new StringBuilder();
    string typeName;

    if (type.IsGenericParameter)
    {
        typeName = type.Name;
    }
    else if (withNamespace)
    {
        typeName = type.Name == "Void" ? "void" : type.FullName;

        if (type.IsNested)
        {
            typeName = typeName.Replace('+', '.');
        }
    }
    else
    {
        typeName = type.Name;

        switch (typeName)
        {
            case "String": return "string";
            case "Int32": return "int";
            case "Int64": return "long";
            case "Double": return "double";
            case "Decimal": return "decimal";
            case "Object": return "object";
            case "Void": return "void";
            default: break;
        }

        if (type.IsNested)
        {
            typeName = type.DeclaringType.GetDisplayName(withNamespace) + "." + typeName;
        }
    }

    if (type.IsNullable())
    {
        return type.GetNullableInnerType().GetDisplayName(withNamespace) + "?";
    }
    else if (type.IsGenericType)
    {
        typeName = typeName.Substring(0, typeName.IndexOf('`'));
        var genericParameters = string.Join(", ", type.GetGenericArguments()
            .Select(item => item.GetDisplayName(withNamespace)));

        return typeName + "<" + genericParameters + ">";
    }
    else
    {
        return typeName;
    }
}

Method to get display name of a parameter.

public static string GetDisplayName(this ParameterInfo parameterInfo, bool withNamespace)
{
    var sb = new StringBuilder();
 
    foreach(var attribute in parameterInfo.GetCustomAttributes(true).Cast<Attribute>())
    {
        sb.Append(attribute.GetDisplayName(withNamespace));
        sb.Append(" ");
    }
 
    sb.Append(parameterInfo.ParameterType.GetDisplayName(withNamespace) + " "
        + parameterInfo.Name);
 
    return sb.ToString();
}

Leave a Reply

Your email address will not be published. Required fields are marked *