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

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.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); private static readonly Type _xPathExtensionsType = Type.GetType("System.Xml.XPath.Extensions, System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); public static string GetXmlDocumentation(this Type type) { return ((MemberInfo)type.GetTypeInfo()).GetXmlDocumentation(); } public static string GetXmlDocumentation(this MemberInfo member) { if ((object)_xPathExtensionsType == null) 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 ((object)_xPathExtensionsType == null) 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 ((MemberInfo)type.GetTypeInfo()).GetXmlDocumentation(pathToXmlFile); } public static string GetXmlDocumentation(this MemberInfo member, string pathToXmlFile) { try { lock (_lock) { if (pathToXmlFile != null && (object)_xPathExtensionsType != null) { AssemblyName name = member.Module.Assembly.GetName(); if (_cache.ContainsKey(name.FullName) && _cache[name.FullName] == null) return string.Empty; if (DynamicFileExists(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 { lock (_lock) { if (pathToXmlFile != null && (object)_xPathExtensionsType != null) { AssemblyName name = parameter.Member.Module.Assembly.GetName(); if (_cache.ContainsKey(name.FullName) && _cache[name.FullName] == null) return string.Empty; if (DynamicFileExists(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 DynamicXPathEvaluate(xml, $"""{new object[1] { memberElementName }}""").ToString().Trim(); } private static string GetXmlDocumentation(this ParameterInfo parameter, XDocument xml) { string memberElementName = GetMemberElementName(parameter.Member); if (parameter.IsRetval || string.IsNullOrEmpty(parameter.Name)) return DynamicXPathEvaluate(xml, $"""{new object[1] { memberElementName }}""").ToString().Trim(); return DynamicXPathEvaluate(xml, string.Format("string(/doc/members/member[@name='{0}']/param[@name='{1}'])", new object[2] { memberElementName, parameter.Name })).ToString().Trim(); } 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 x.ParameterType.FullName).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 string.Format("{0}:{1}", new object[2] { c, text }); } private static string GetXmlDocumentationPath(dynamic assembly) { dynamic val = assembly.GetName(); dynamic val2 = XmlDocumentationExtensions.DynamicPathCombine(XmlDocumentationExtensions.DynamicPathGetDirectoryName(assembly.Location), val.Name + ".xml"); if (XmlDocumentationExtensions.DynamicFileExists(val2)) return (string)val2; dynamic value = Type.GetType("System.AppDomain").GetRuntimeProperty("CurrentDomain").GetValue(null); return (string)XmlDocumentationExtensions.DynamicPathCombine(value.BaseDirectory, val.Name + ".xml"); } private static bool DynamicFileExists(string filePath) { return (bool)Type.GetType("System.IO.File", true).GetRuntimeMethod("Exists", new Type[1] { typeof(string) }).Invoke(null, new object[1] { filePath }); } private static string DynamicPathCombine(string path1, string path2) { return (string)Type.GetType("System.IO.Path", true).GetRuntimeMethod("Combine", new Type[2] { typeof(string), typeof(string) }).Invoke(null, new object[2] { path1, path2 }); } private static string DynamicPathGetDirectoryName(string filePath) { return (string)Type.GetType("System.IO.Path", true).GetRuntimeMethod("GetDirectoryName", new Type[1] { typeof(string) }).Invoke(null, new object[1] { filePath }); } private static object DynamicXPathEvaluate(XDocument document, string path) { return (string)_xPathExtensionsType.GetRuntimeMethod("XPathEvaluate", new Type[2] { typeof(XDocument), typeof(string) }).Invoke(null, new object[2] { document, path }); } } }