using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Diagnostics; using System.Xml; namespace DocGenerator { internal class Program { internal class CommentBlock { public string MethodComment { get; set; } = string.Empty; public Dictionary ParametersComment { get; set; } = new Dictionary(); public string ReturnComment { get; set; } = string.Empty; } private static CommentBlock ParseComment(string comment) { CommentBlock block = new(); string newComment = "\n" + comment.Replace("///", "") + ""; XmlDocument? xmlDoc = new(); try { xmlDoc.LoadXml(newComment); } catch { return block; } XmlNode? summaryNode = xmlDoc.SelectSingleNode("//summary"); string? methodSummary = summaryNode?.InnerText.Trim(); XmlNodeList? paramNodes = xmlDoc.SelectNodes("//param"); if (paramNodes != null) { foreach (XmlNode paramNode in paramNodes) { string? paramName = paramNode?.Attributes?["name"]?.Value; string? paramDescription = paramNode?.InnerText.Trim(); if (paramName != null) { if (block.ParametersComment.ContainsKey(paramName)) { block.ParametersComment[paramName] = paramDescription ?? ""; } else { block.ParametersComment.Add(paramName, paramDescription ?? ""); } } } } XmlNode? returnsNode = xmlDoc.SelectSingleNode("//returns"); string? returnsDescription = returnsNode?.InnerText.Trim(); block.MethodComment = methodSummary ?? ""; block.ReturnComment = returnsDescription ?? ""; return block; } private static void ParseClass(ClassDeclarationSyntax classDeclaration) { string className = classDeclaration.Identifier.ValueText; Directory.CreateDirectory(className); var methodDeclarations = classDeclaration.Members.OfType(); foreach (MethodDeclarationSyntax methodDeclaration in methodDeclarations) { // 忽略非 public 方法 if (methodDeclaration.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PublicKeyword))) { string methodName = methodDeclaration.Identifier.ValueText; string ReturnType = methodDeclaration.ReturnType.ToString(); // 忽略点击事件 if (methodName.EndsWith("Click")) { continue; } // 获取注释 string comment = methodDeclaration.GetLeadingTrivia().ToString(); CommentBlock commentBlock = ParseComment(comment); using var streamerWriter = File.CreateText(Path.Combine(className, $"{methodName}.md")); streamerWriter.WriteLine($"# {methodName}\n"); streamerWriter.WriteLine("## 定义\n"); streamerWriter.WriteLine(commentBlock.MethodComment + "\n"); /// 方法原型 streamerWriter.WriteLine("```CSharp"); streamerWriter.WriteLine(methodDeclaration.ToString().Split("\n")[0]); streamerWriter.WriteLine("```"); streamerWriter.WriteLine(); streamerWriter.WriteLine("## 请求参数\n"); if (methodDeclaration.ParameterList.Parameters.Count > 0) { streamerWriter.WriteLine("| 参数 | 类型 | 约束 | 说明 |"); streamerWriter.WriteLine("| - | - | - | - |"); } foreach (var parameter in methodDeclaration.ParameterList.Parameters) { var paramName = parameter.Identifier.ValueText; var paramType = parameter.Type.ToString(); var desc = string.Empty; if (commentBlock.ParametersComment.ContainsKey(paramName)) { desc = commentBlock.ParametersComment[paramName]; } streamerWriter.WriteLine($"| {paramName} | {paramType} | | {desc} |"); } streamerWriter.WriteLine("\n"); streamerWriter.WriteLine("## 返回\n"); streamerWriter.WriteLine($"类型: {ReturnType}"); streamerWriter.WriteLine(commentBlock.ReturnComment); streamerWriter.WriteLine("\n"); streamerWriter.WriteLine("## 请求示例\n"); streamerWriter.WriteLine("## 错误处理\n"); streamerWriter.WriteLine("## 注意事项\n"); } } } private static void ParseFile(string filePath) { string code = File.ReadAllText(filePath); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); CompilationUnitSyntax root = syntaxTree.GetCompilationUnitRoot(); var classDeclarations = root.Members.OfType() .SelectMany(namespaceDeclaration => namespaceDeclaration.Members) .OfType(); foreach (var classDeclaration in classDeclarations) { ParseClass(classDeclaration); } } static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine($"Usage: {Process.GetCurrentProcess().ProcessName} "); return; } ParseFile(@"D:\project\Drawer\Drawer\UCDraw\UCDraw\UC\MainView.cs"); } } }