Page 41 - MSDN Magazine, October 2019
P. 41

Figure 8 Loading XML Documentation from Assembly
Figure 9 Usage Examples
public static string GetDirectoryPath(this Assembly assembly) \{
string codeBase = assembly.CodeBase; UriBuilder uri = new UriBuilder(codeBase); string path = Uri.UnescapeDataString(uri.Path); return Path.GetDirectoryName(path);
\}
internal static HashSet<Assembly> loadedAssemblies = new HashSet<Assembly>();
internal static void LoadXmlDocumentation(Assembly assembly) \{
if (loadedAssemblies.Contains(assembly)) \{ return; // Already loaded
\}
string directoryPath = assembly.GetDirectoryPath();
string xmlFilePath = Path.Combine(directoryPath, assembly.GetName().Name + ".xml"); if (File.Exists(xmlFilePath)) \{
LoadXmlDocumentation(File.ReadAllText(xmlFilePath));
loadedAssemblies.Add(assembly); \}
\}
// Optional loading function LoadXmlDocumentation(File.ReadAllText("PATH/TO/XML/FILE.xml"));
// Write the documentation of all types to the console
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) \{
Console.WriteLine(type.GetDocumentation()); \}
// Write all the documentation of every member to the console foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) \{
foreach (MemberInfo memberInfo in type.GetMembers()) \{ Console.WriteLine(memberInfo.GetDocumentation());
\} \}
// Write all the documentation of every parameter to the console foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) \{
foreach (MemberInfo memberInfo in type.GetMembers()) \{ if (memberInfo is MethodBase) \{
MethodBase methodBase = memberInfo as MethodBase;
foreach (ParameterInfo parameterInfo in methodBase.GetParameters()) \{
Console.WriteLine(parameterInfo.GetDocumentation()); \}
\} \}
\}
The most obvious use case for this code is documentation gen- eration. You could easily reflect through all the types and members in your assembly, grab the XML documentation from them, and dump that documentation into any format you want.
There are multiple documentation generators out there, but they’re often rather restrictive as to their output formats. What I wanted was to dump all the documentation into a simple HTML tree that I could style myself. So, writing my own documentation generator using this methodology was the easiest solution. Also, none of the documentation generators are able to handle my custom XML tags. Here are examples of custom XML tags to give you some tag ideas:
• notes: adding additional documentation outside the standard tags • revision: help document the history of a member
• todo: mark members for future development
• link: URL link to further documentation and/or videos
• critical: mark members that are critical for external projects and shouldn’t be edited
• bug: express a known bug in a member until it can be fixed • test: link to the unit tests for a member, or perhaps metadata
for the unit testing
• runtime: big O-notation runtime complexity • citation: crediting sources for code
If you write a documentation Web site generator that makes use of these kinds of tags and you use continuous integration to deploy the Web site on code commits, then notifying users of bugs could be as simple as adding the “bug” XML tag to one of your members in source code. Nice.
You could also use XML documentation for code analysis. If you use standardized XML tags like “runtime,” it may help you resolve hot spots in code. If one method is documented to have a runtime complexity of “O(n),” while another overload of the method has a runtime complexity of “O(ln(n)),” you’d clearly want to use the lat- ter if possible. Theoretically, this could be added to code analyzers or possibly Visual Studio extensions to offer coding suggestions.
There are already compilation warnings to encourage XML documentation on publicly visible types and members in .NET code, but there aren’t any warnings to encourage people to use the “exception” tag. Being able to grab the XML through reflection
msdnmagazine.com
may allow you to more easily find members that don’t meet devel- opment and documentation standards.
Important Mentions
This solution is not future proof. As new features are added in future versions of languages like C# and Visual Basic, the format of the XML file may change. It’s unlikely that backward compatibility would be broken, but new features with new XML formats would require the extension methods to be modified to deal with them.
XML documentation and attributes are very similar. Both appear above members in code providing metadata about the member. How- ever, XML documentation shouldn’t be considered an alternative to attributes. Attributes are guaranteed to be reachable at runtime, be- cause they’re included in the compiled code. Any metadata necessary for the functionality of code should be implemented as an attribute.
I encourage you to look at the code in my Towel project on GitHub (github.com/ZacharyPatten/Towel). There are also unit tests for the code within the project. I’m sure there’s plenty of room for improvement in the code, and probably some test cases I missed when testing it. Youcouldgoastepfurtherandwriteextensionmethodoverloads that take string parameters to extract specific tags from the XML, such as grabbing the “summary” content specifically.
I hope it’s now clear that you can indeed access XML documen- tation easily via reflection. Probably the biggest drawback is having to make sure that the XML exists in the necessary file location so it can be loaded into memory. Just be sure to check that the files exist, and this technique should do the trick until a better meth- odology comes along. n
Zachary Patten is just another programmer who likes coffee, Power Rangers and dogs. He graduated from Kansas State University, and currently has approximately five years of professional programming experience.
thanks to the following Microsoft technical experts for reviewing this article: Den Delimaschi, Bill Wagner
October 2019 37

















































   39   40   41   42   43