Skip to content

如何获取类中字段、属性、函数等的相关注释

情境

新开UE5项目,需要把老项目中的C#接口通过工具转换成UE5项目接口代码,几百个接口不可能手动一个一个改不现实,那么就需要获取C#接口中的参数和返回结构中字段注释。

搜索了一下网上绝大部分都是给字段配置自定义属性,然后通过配置Attribute来获取注释,没有特别强制要求,99.999% 的人都不会按照这种方式去写注释,这种方式是极其不靠谱的

相关链接:C# 反射 读取 类的 类注释,方法注释,属性注释

"img"

你会这么写注释吗?我估计你回来句:"神经病啊,这么写注释"。正常的情况是这样

csharp
/// <summary>
/// Person基类
/// </summary>
public class Person
{
 /// <summary>
 /// 年龄
 /// </summary>
 public int age;
 /// <summary>
 /// 姓名
 /// </summary>
 public string name;
 /// <summary>
 /// 获取用户信息
 /// </summary>
 /// <returns></returns>
 public string GetUserInfo()
 {
  return name + " " + age + "岁";
 }
}

想获取以上的类名对应的注释、字段对应的注释、方法对应的注释,效果如下:

"img"

实现代码

csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

/// <summary>
/// Person基类
/// </summary>
public class Person
{
    /// <summary>
    /// 年龄
    /// </summary>
    public int age;
    /// <summary>
    /// 姓名
    /// </summary>
    public string name;
    /// <summary>
    /// 获取用户信息
    /// </summary>
    /// <returns></returns>
    public string GetUserInfo()
    {
        return name + " " + age + "岁";
    }

    static void Main(string[] args)
    {
        GetClassInfo("Person");
        Console.ReadKey();
    }

    private static void GetClassInfo(string className)
    {
        Type classType = Type.GetType(className);
        if (classType != null)
        {
            var xmlDoc = LoadXMLDoc();
            Console.WriteLine(GetClassComment(xmlDoc, className));

            PropertyInfo[] properties = classType.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                StringBuilder builder = new StringBuilder();
                builder.Append(GetPropertyComment(xmlDoc, property));
                builder.Append("\n");

                //属性类型
                builder.Append(property.PropertyType.Name);
                builder.Append(" ");

                // 获取属性名
                builder.Append(property.Name);
                builder.Append("\n");

                Console.WriteLine(builder.ToString());
            }

            var fields = classType.GetFields();
            foreach (var field in fields)
            {
                StringBuilder builder = new StringBuilder();
                builder.Append(GetFieldComment(xmlDoc, field));
                builder.Append("\n");

                //字段类型
                builder.Append(field.FieldType);
                builder.Append(" ");

                //字段名
                builder.Append(field.Name);
                builder.Append("\n");

                Console.WriteLine(builder.ToString());
            }

            var methods = classType.GetMethods();
            foreach (var method in methods)
            {
                StringBuilder builder = new StringBuilder();
                builder.Append(GetMethodComment(xmlDoc, string.Format("{0}.{1}", className, method.Name)));
                builder.Append("\n");

                builder.Append(method.Name);
                builder.Append("\n");

                Console.WriteLine(builder.ToString());
            }
        }
        else
        {
            Console.WriteLine(className + "not found.");
        }
    }

    private static XmlDocument LoadXMLDoc()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(assembly.Location.TrimEnd(".exe".ToCharArray()) + ".xml");
        return xmlDoc;
    }

    private static string GetClassComment(XmlDocument xmlDoc, string className)
    {
        string memberName = $"T:{className}";
        XmlNode memberNode = xmlDoc.SelectSingleNode($"//member[starts-with(@name, '{memberName}')]");

        if (memberNode != null)
        {
            return memberNode.InnerText.Trim();
        }

        return string.Empty;
    }

    private static string GetMethodComment(XmlDocument xmlDoc, string methodName)
    {
        string memberName = $"M:{methodName}";
        XmlNode memberNode = xmlDoc.SelectSingleNode($"//member[starts-with(@name, '{memberName}')]");

        if (memberNode != null)
        {
            return memberNode.InnerText.Trim();
        }

        return string.Empty;
    }

    private static string GetPropertyComment(XmlDocument xmlDoc, PropertyInfo property)
    {
        string memberName = $"P:{property.DeclaringType.FullName}.{property.Name}";
        XmlNode memberNode = xmlDoc.SelectSingleNode($"//member[starts-with(@name, '{memberName}')]");

        if (memberNode != null)
        {
            return memberNode.InnerText.Trim();
        }

        return string.Empty;
    }

    private static string GetFieldComment(XmlDocument xmlDoc, FieldInfo fieldInfo)
    {
        string memberName = $"F:{fieldInfo.DeclaringType.FullName}.{fieldInfo.Name}";
        XmlNode memberNode = xmlDoc.SelectSingleNode($"//member[starts-with(@name, '{memberName}')]");

        if (memberNode != null)
        {
            return memberNode.InnerText.Trim();
        }

        return string.Empty;
    }
}

看到以上代码你肯定会问xml 如何来的?为什么完全按照你的代码创建的项目,我怎么没有这个xml文件。

操作步骤:打开编译生成xml即可,右键项目属性

"img"

再次编译生成就会产生对应的xml了,这个xml会包含所有注释信息,打开看下即可知道

"img"

想要其他注释,对应着配置就可以了

Released under the MIT License.