/ModularEngine/src/DocsByReflection/DocsByReflection.cs
# · C# · 225 lines · 135 code · 26 blank · 64 comment · 13 complexity · ce5bab9ae046661434fc62692ab4115c MD5 · raw file
- //Except where stated all code and programs in this project are the copyright of Jim Blackler, 2008.
- //jimblackler@gmail.com
- //
- //This is free software. Libraries and programs are distributed under the terms of the GNU Lesser
- //General Public License. Please see the files COPYING and COPYING.LESSER.
-
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Reflection;
- using System.Xml;
-
- namespace JimBlackler.DocsByReflection
- {
- /// <summary>
- /// Utility class to provide documentation for various types where available with the assembly
- /// </summary>
- public class DocsByReflection
- {
- /// <summary>
- /// Provides the documentation comments for a specific method
- /// </summary>
- /// <param name="methodInfo">The MethodInfo (reflection data ) of the member to find documentation for</param>
- /// <returns>The XML fragment describing the method</returns>
- public static XmlElement XMLFromMember(MethodInfo methodInfo)
- {
- string parametersString = ParametersToName(methodInfo.GetParameters());
-
- //AL: 15.04.2008 ==> BUG-FIX remove () if parametersString is empty
- if (parametersString.Length > 0)
- return XMLFromName(methodInfo.DeclaringType, 'M', methodInfo.Name + "(" + parametersString + ")");
- else
- return XMLFromName(methodInfo.DeclaringType, 'M', methodInfo.Name);
- }
-
- /// <summary>
- /// Converts an array of parameters to its string representation
- /// </summary>
- /// <param name="parameters">An array of parameters</param>
- /// <returns>The string representation of the given parameters</returns>
- public static string ParametersToName(ParameterInfo[] parameters)
- {
- // Calculate the parameter string as this is in the member name in the XML
- string ret = "";
- foreach (ParameterInfo parameterInfo in parameters)
- {
- if (ret.Length > 0)
- ret += ",";
- ret += TypeToName(parameterInfo.ParameterType);
- }
- return ret;
- }
-
- /// <summary>
- /// Converts a (possibly generic) type to its string representation
- /// </summary>
- /// <param name="type">A System.Type that needs to be represented as string</param>
- /// <returns>The string representation of the given type</returns>
- public static string TypeToName(Type type)
- {
- if (type.IsGenericType) {
- string ret = "";
- ret += type.Namespace;
- ret += ".";
- if (type.Name.Contains("`1"))
- ret += type.Name.Substring(0, type.Name.IndexOf('`'));
- else
- ret += type.Name;
- ret += "{";
- string typeParams = "";
- foreach (Type paramType in type.GetGenericArguments()) {
- if (typeParams.Length > 0)
- typeParams += ",";
- typeParams += TypeToName(paramType);
- }
- ret += typeParams;
- ret += "}";
- return ret;
- } else {
- return type.FullName;
- }
- }
-
- /// <summary>
- /// Provides the documentation comments for a specific member
- /// </summary>
- /// <param name="memberInfo">The MemberInfo (reflection data) or the member to find documentation for</param>
- /// <returns>The XML fragment describing the member</returns>
- public static XmlElement XMLFromMember(MemberInfo memberInfo)
- {
- // First character [0] of member type is prefix character in the name in the XML
- return XMLFromName(memberInfo.DeclaringType, memberInfo.MemberType.ToString()[0], memberInfo.Name);
- }
-
- /// <summary>
- /// Provides the documentation comments for a specific type
- /// </summary>
- /// <param name="type">Type to find the documentation for</param>
- /// <returns>The XML fragment that describes the type</returns>
- public static XmlElement XMLFromType(Type type)
- {
- // Prefix in type names is T
- return XMLFromName(type, 'T', "");
- }
-
- /// <summary>
- /// Obtains the XML Element that describes a reflection element by searching the
- /// members for a member that has a name that describes the element.
- /// </summary>
- /// <param name="type">The type or parent type, used to fetch the assembly</param>
- /// <param name="prefix">The prefix as seen in the name attribute in the documentation XML</param>
- /// <param name="name">Where relevant, the full name qualifier for the element</param>
- /// <returns>The member that has a name that describes the specified reflection element</returns>
- private static XmlElement XMLFromName(Type type, char prefix, string name)
- {
- string fullName;
-
- if (String.IsNullOrEmpty(name))
- {
- fullName = prefix + ":" + type.FullName;
- }
- else
- {
- fullName = prefix + ":" + type.FullName + "." + name;
- }
-
- fullName = fullName.Replace("+", ".");
-
- XmlDocument xmlDocument = XMLFromAssembly(type.Assembly);
-
- XmlElement matchedElement = null;
-
- foreach (XmlElement xmlElement in xmlDocument["doc"]["members"])
- {
- if (xmlElement.Attributes["name"].Value.Equals(fullName))
- {
- if (matchedElement != null)
- {
- throw new DocsByReflectionException("Multiple matches to query", null);
- }
-
- matchedElement = xmlElement;
- }
- }
-
- return matchedElement;
- }
-
- /// <summary>
- /// A cache used to remember Xml documentation for assemblies
- /// </summary>
- static Dictionary<Assembly, XmlDocument> cache = new Dictionary<Assembly, XmlDocument>();
-
- /// <summary>
- /// A cache used to store failure exceptions for assembly lookups
- /// </summary>
- static Dictionary<Assembly, Exception> failCache = new Dictionary<Assembly, Exception>();
-
- /// <summary>
- /// Obtains the documentation file for the specified assembly
- /// </summary>
- /// <param name="assembly">The assembly to find the XML document for</param>
- /// <returns>The XML document</returns>
- /// <remarks>This version uses a cache to preserve the assemblies, so that
- /// the XML file is not loaded and parsed on every single lookup</remarks>
- public static XmlDocument XMLFromAssembly(Assembly assembly)
- {
- if (failCache.ContainsKey(assembly))
- {
- throw failCache[assembly];
- }
-
- try
- {
-
- if (!cache.ContainsKey(assembly))
- {
- // load the docuemnt into the cache
- cache[assembly] = XMLFromAssemblyNonCached(assembly);
- }
-
- return cache[assembly];
- }
- catch (Exception exception)
- {
- failCache[assembly] = exception;
- throw exception;
- }
- }
-
- /// <summary>
- /// Loads and parses the documentation file for the specified assembly
- /// </summary>
- /// <param name="assembly">The assembly to find the XML document for</param>
- /// <returns>The XML document</returns>
- private static XmlDocument XMLFromAssemblyNonCached(Assembly assembly)
- {
- string assemblyFilename = assembly.CodeBase;
-
- const string prefix = "file:///";
-
- if (assemblyFilename.StartsWith(prefix))
- {
- StreamReader streamReader;
-
- try
- {
- streamReader = new StreamReader(Path.ChangeExtension(assemblyFilename.Substring(prefix.Length), ".xml"));
- }
- catch (FileNotFoundException exception)
- {
- throw new DocsByReflectionException("XML documentation not present (make sure it is turned on in project properties when building)", exception);
- }
-
- XmlDocument xmlDocument = new XmlDocument();
- xmlDocument.Load(streamReader);
- return xmlDocument;
- }
- else
- {
- throw new DocsByReflectionException("Could not ascertain assembly filename", null);
- }
- }
- }
- }