using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Xml.Linq; using System.Reflection; using ProtoBuf; using Grpc.Extension.BaseService.Model; namespace Grpc.Extension.Common.Internal { internal static class ProtoCommentGenerator { //Xml文档注释 static List xmlComments = new List(); //ProtoType static List protoTypes; static ProtoCommentGenerator() { #if DEBUG string path = Environment.CurrentDirectory; string[] temp = path.Split("\\".ToCharArray()); string patha = ""; for (int i = 0; i < temp.Length - 1; i++) { patha += temp[i]; patha += "\\"; } var files = Directory.GetFiles(patha, "*.xml", SearchOption.AllDirectories); Dictionary keys = new Dictionary(); foreach (string file in files) { string[] p= file.Split("\\".ToCharArray()); string fileName = p[p.Length - 1]; keys[fileName] = file; } List fils = new List(); foreach (string file in keys.Keys) { fils.Add(keys[file]); } #else //加载注释xml文件 var fils = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml"); #endif var assembliyNames = new List(); foreach (var file in fils) { var xe = XElement.Load(file); //检查是否为注释xml文件 if (xe.Element("assembly") == null || xe.Element("members") == null) continue; assembliyNames.Add(xe.Element("assembly").Value); foreach (var item in xe.Element("members").Elements()) { var name = item.Attribute("name")?.Value; //bool flag = false; //foreach (XmlCommentInfo commentInfo in xmlComments) { // if (name.Equals(commentInfo.FullName)) { // flag = true; // } //} //if (flag) { // continue; //} var nameArr = name?.Split(':'); if (name != null && nameArr.Length > 1) { xmlComments.Add(new XmlCommentInfo() { FullName = nameArr[1], Type = nameArr[0], Summary = item.Element("summary")?.Value?.Trim() }); } } } //初始化protoTypes var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(p => assembliyNames.Contains(p.GetName().Name)); protoTypes = assemblies.SelectMany(p => p.GetTypes().Where(t => t.GetCustomAttribute() != null)).ToList(); } /// /// 获取注释集合 /// /// /// /// public static Dictionary GetComments(string[] types,string fullName) { return xmlComments.Where(p => types.Contains(p.Type) && p.FullName.StartsWith(fullName)).ToDictionary(p => p.FullName, p => p.Summary); } /// /// 获取注释 /// /// /// /// public static string GetComment(string type, string fullName) { return xmlComments.FirstOrDefault(p => p.Type == type && p.FullName.StartsWith(fullName))?.Summary; } /// /// 给Message加入注释 /// /// /// /// public static string AddMessageComment(this string proto) { var dicComment = new Dictionary(); var lines = new List(); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(proto))) using (var sr = new StreamReader(ms)) { while (sr.Peek() > 0) { var line = sr.ReadLine(); var lineArr = line.Split(new string[]{ " ", "repeated" },StringSplitOptions.RemoveEmptyEntries); if (lineArr.Length > 1) { var typeName = lineArr[1];//message和enum后的类型名 if (ProtoGenerator.protoMsgStartWithKeywords.Any(q => line.StartsWith(q))) { var fullName = GetProtoTypeFullName(typeName); if(!string.IsNullOrEmpty(fullName)) dicComment = GetComments(new string[] { "T", "P","F" }, fullName); } var propertyName = lineArr[1];//属性名 var comment = dicComment.FirstOrDefault(p => p.Key.EndsWith("." + propertyName)).Value; if (!string.IsNullOrWhiteSpace(comment)) { if (line.EndsWith(";")) { lines.Add(AddComment(comment, " ")); } else { lines.Add(AddComment(comment)); } } } lines.Add(line); } } return string.Join(Environment.NewLine, lines); } //添加注释(多行注释) private static string AddComment(string comment, string prefix = "") { var arr = comment.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); return string.Join(Environment.NewLine, arr.Select(p => $"{prefix}//{p.TrimStart()}")); } /// /// 根据名字获取ProtoType的FullName /// /// /// /// private static string GetProtoTypeFullName(string name) { //判断TEntity是否就是要获取的类型 if (typeof(TEntity).Name == name) return typeof(TEntity).FullName; //从protoTypes里获取 var type = protoTypes.Where(t => t.Name == name).FirstOrDefault(); return type?.FullName; } /// /// 给Service加入注释 /// /// /// public static void AddServiceComment(ProtoMethodInfo proto,StringBuilder sb) { var comment = string.Empty; var handler = MetaModel.Methods.FirstOrDefault(p => p.FullName == proto.FullName)?.Handler; if (handler != null) { //var fullName = handler.Method.GetPropertyValue("FullName", BindingFlags.Instance | BindingFlags.NonPublic); var fullName = GetMethodFullName(handler.Method); //将方法的FullName转换成注释的FullName var xmlFullName = fullName.Replace(" ", "").Replace("`1[", "{").Replace("]", "}"); comment = GetComment("M", xmlFullName); if (!string.IsNullOrWhiteSpace(comment)) { sb.AppendLine(AddComment(comment, " ")); } } } /// /// 获取方法的FullName /// /// /// private static string GetMethodFullName(MethodInfo method) { var parameters = method.GetParameters(); var paraStr = string.Join(",", parameters.Select(p => p.ParameterType.ToString())); return $"{method.DeclaringType.FullName}.{method.Name}({paraStr})"; } } }