<PackageReference Include="NJsonSchema" Version="4.0.6074.30968" />

XmlDocumentationExtensions

public static class XmlDocumentationExtensions
Provides extension methods for reading XML comments from reflected members.
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Xml.Linq; namespace NJsonSchema.Infrastructure { public static class XmlDocumentationExtensions { private static readonly object Lock = new object(); private static readonly Dictionary<string, XDocument> Cache = new Dictionary<string, XDocument>(StringComparer.OrdinalIgnoreCase); public static string GetXmlDocumentation(this MemberInfo member) { if (!DynamicApis.SupportsXPathApis || !DynamicApis.SupportsFileApis) return string.Empty; lock (Lock) { AssemblyName name = member.Module.Assembly.GetName(); if (Cache.ContainsKey(name.FullName) && Cache[name.FullName] == null) return string.Empty; return member.GetXmlDocumentation(GetXmlDocumentationPath(member.Module.Assembly)); } } public static string GetXmlDocumentation(this ParameterInfo parameter) { if (!DynamicApis.SupportsXPathApis || !DynamicApis.SupportsFileApis) return string.Empty; lock (Lock) { AssemblyName name = parameter.Member.Module.Assembly.GetName(); if (Cache.ContainsKey(name.FullName) && Cache[name.FullName] == null) return string.Empty; return parameter.GetXmlDocumentation(GetXmlDocumentationPath(parameter.Member.Module.Assembly)); } } public static string GetXmlDocumentation(this Type type, string pathToXmlFile) { return type.GetTypeInfo().GetXmlDocumentation(pathToXmlFile); } public static string GetXmlDocumentation(this MemberInfo member, string pathToXmlFile) { try { if (pathToXmlFile != null && DynamicApis.SupportsXPathApis && DynamicApis.SupportsFileApis) { lock (Lock) { AssemblyName name = member.Module.Assembly.GetName(); if (Cache.ContainsKey(name.FullName) && Cache[name.FullName] == null) return string.Empty; if (DynamicApis.FileExists(pathToXmlFile)) { if (!Cache.ContainsKey(name.FullName)) Cache[name.FullName] = XDocument.Load(pathToXmlFile); return member.GetXmlDocumentation(Cache[name.FullName]); } Cache[name.FullName] = null; return string.Empty; } } return string.Empty; } catch { return string.Empty; } } public static string GetXmlDocumentation(this ParameterInfo parameter, string pathToXmlFile) { try { if (pathToXmlFile != null && DynamicApis.SupportsXPathApis && DynamicApis.SupportsFileApis) { lock (Lock) { AssemblyName name = parameter.Member.Module.Assembly.GetName(); if (Cache.ContainsKey(name.FullName) && Cache[name.FullName] == null) return string.Empty; if (DynamicApis.FileExists(pathToXmlFile)) { if (!Cache.ContainsKey(name.FullName)) Cache[name.FullName] = XDocument.Load(pathToXmlFile); return parameter.GetXmlDocumentation(Cache[name.FullName]); } Cache[name.FullName] = null; return string.Empty; } } return string.Empty; } catch { return string.Empty; } } private static string GetXmlDocumentation(this MemberInfo member, XDocument xml) { string memberElementName = GetMemberElementName(member); return RemoveLineBreakWhiteSpaces(DynamicApis.XPathEvaluate(xml, $"""{memberElementName}""").ToString().Trim()); } private static string GetXmlDocumentation(this ParameterInfo parameter, XDocument xml) { string memberElementName = GetMemberElementName(parameter.Member); string documentation = (!parameter.IsRetval && !string.IsNullOrEmpty(parameter.Name)) ? DynamicApis.XPathEvaluate(xml, $"""{memberElementName}""{parameter.Name}""").ToString().Trim() : DynamicApis.XPathEvaluate(xml, $"""{memberElementName}""").ToString().Trim(); return RemoveLineBreakWhiteSpaces(documentation); } private static string RemoveLineBreakWhiteSpaces(string documentation) { return Regex.Replace(documentation.Replace("\r", string.Empty), "\\n\\s+", "\n"); } private static string GetMemberElementName(dynamic member) { string text = (string)((member is Type) ? ((Type)member).FullName : (member.DeclaringType.FullName + "." + member.Name)); char c; switch ((string)member.MemberType.ToString()) { case "Constructor": text = text.Replace(".ctor", "#ctor"); goto case "Method"; case "Method": { c = 'M'; string text2 = string.Join(",", (from x in ((MethodBase)member).GetParameters() select Regex.Replace(x.ParameterType.FullName, "(`[0-9]+)|(, .*?PublicKeyToken=[0-9a-z]*)", string.Empty).Replace("[[", "{").Replace("]]", "}")).ToArray()); if (!string.IsNullOrEmpty(text2)) text = text + "(" + text2 + ")"; break; } case "Event": c = 'E'; break; case "Field": c = 'F'; break; case "NestedType": text = text.Replace('+', '.'); goto case "TypeInfo"; case "TypeInfo": c = 'T'; break; case "Property": c = 'P'; break; default: throw new ArgumentException("Unknown member type.", "member"); } return $"{c}""{text}"; } private static string GetXmlDocumentationPath(dynamic assembly) { try { if (!((assembly == null) ? true : false)) { if (!(string.IsNullOrEmpty(assembly.Location) ? true : false)) { dynamic val = assembly.GetName(); if (!(string.IsNullOrEmpty(val.Name) ? true : false)) { dynamic val2 = DynamicApis.PathCombine(DynamicApis.PathGetDirectoryName(assembly.Location), val.Name + ".xml"); if (!(DynamicApis.FileExists(val2) ? true : false)) { dynamic value = ReflectionExtensions.GetValue(Type.GetType("System.AppDomain").GetRuntimeProperty("CurrentDomain"), null); val2 = DynamicApis.PathCombine(value.BaseDirectory, val.Name + ".xml"); if (!(DynamicApis.FileExists(val2) ? true : false)) return (string)DynamicApis.PathCombine(value.BaseDirectory, "bin\\" + val.Name + ".xml"); return (string)val2; } return (string)val2; } return null; } return null; } return null; } catch { return null; } } } }