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);
public static string GetXmlDocumentation(this Type type)
{
return ((MemberInfo)type.GetTypeInfo()).GetXmlDocumentation();
}
public static string GetXmlDocumentation(this MemberInfo member)
{
if (!FullDotNetMethods.SupportsFullDotNetMethods)
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 (!FullDotNetMethods.SupportsFullDotNetMethods)
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 && FullDotNetMethods.SupportsFullDotNetMethods) {
AssemblyName name = member.Module.Assembly.GetName();
if (_cache.ContainsKey(name.FullName) && _cache[name.FullName] == null)
return string.Empty;
if (FullDotNetMethods.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 {
lock (_lock) {
if (pathToXmlFile != null && FullDotNetMethods.SupportsFullDotNetMethods) {
AssemblyName name = parameter.Member.Module.Assembly.GetName();
if (_cache.ContainsKey(name.FullName) && _cache[name.FullName] == null)
return string.Empty;
if (FullDotNetMethods.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 FullDotNetMethods.XPathEvaluate(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 FullDotNetMethods.XPathEvaluate(xml, $"""{new object[1] {
memberElementName
}}""").ToString().Trim();
return FullDotNetMethods.XPathEvaluate(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 = FullDotNetMethods.PathCombine(FullDotNetMethods.PathGetDirectoryName(assembly.Location), val.Name + ".xml");
if (FullDotNetMethods.FileExists(val2))
return (string)val2;
dynamic value = Type.GetType("System.AppDomain").GetRuntimeProperty("CurrentDomain").GetValue(null);
val2 = FullDotNetMethods.PathCombine(value.BaseDirectory, val.Name + ".xml");
if (FullDotNetMethods.FileExists(val2))
return (string)val2;
return (string)FullDotNetMethods.PathCombine(value.BaseDirectory, "bin\\" + val.Name + ".xml");
}
}
}