views:

377

answers:

4

Visual Studio does it; Reflector does it; and now I want to as well :)

I want to retrieve the xml documentation for some members in some framework assemblies (i.e. mscorlib.dll, System.dll, etc). I assume this would involve:

  • finding the xml file for the assembly,
  • navigating to the appropriately named child element, and
  • retrieving the desired items (<summary>, <remarks>, etc)


Where are the xml files kept for framework assemblies? Any points on deciphering the xmldoc naming scheme? Are there any libraries out there that will make this process easier?

A: 

The XML file is named exactly like the assembly's file, except for the different 'xml' extension and must be located in the same directory as the assembly itself.

Can't help you with the other two questions, though. AFAIK, you're on your own...

Omer van Kloeten
+2  A: 

Find xml

For assembly.dll it is named as assembly.xml, but installed by Framework SDK, Runtime itself doesn't contain .xml files. Users do not need API documentation.

Location is a bit more complex. It can be side by side with the dll, in the subdirectory named after current locale (e.g. C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\en) or even in some weird directory nearby. I would suggest searching for it in the way runtime looks for satellite assemblies.

Find element

To find element, you should prepare so called "xml-doc ID" from the metadata. AFAIR it is documented in C# language spec, and a bit in MSDN. See Processing XML documentation.

Ilya Ryzhenkov
+1  A: 

Based on Ilya's response:

Find xml

.NET fallback locations (ignoring GAC and other irrelevant subdirectories)

static FileInfo GetXmlDocFile( Assembly assembly ) {
  string assemblyDirPath = Path.GetDirectoryName( assembly.Location );
  string fileName = Path.GetFileNameWithoutExtension( assembly.Location ) +".xml";

  return GetFallbackDirectories( CultureInfo.CurrentCulture )
    .Select( dirName => CombinePath( assemblyDirPath, dirName, fileName ) )
    .Select( filePath => new FileInfo( filePath ) )
    .Where( file => file.Exists )
    .First( );
}

static IEnumerable<string> GetFallbackDirectories( CultureInfo culture ) {
  return culture
    .Enumerate( c => c.Parent.Name != c.Name ? c.Parent : null )
    .Select( c => c.Name );
}

static IEnumerable<T> Enumerate<T>( this T start, Func<T, T> next ) {
  for( T item = start; !object.Equals( item, default(T) ); item = next( item ) )
    yield return item;
}

static string CombinePath( params string[] args ) {
  return args.Aggregate( Path.Combine );
}

Find element

Processing XML Documentation

static XElement GetDocMember( XElement docMembers, MemberInfo member ) {
  string memberId = GetMemberId( member );
  return docMembers.Elements( "member" )
    .Where( e => e.Attribute( "name" ).Value == memberId )
    .First( );
}

static string GetMemberId( MemberInfo member ) {
  char memberKindPrefix = GetMemberPrefix( member );
  string memberName = GetMemberFullName( member );
  return memberKindPrefix + ":" + memberName;
}

static char GetMemberPrefix( MemberInfo member ) {
  return member.GetType( ).Name
    .Replace( "Runtime", "" )[0];
}

static string GetMemberFullName( MemberInfo member ) {
  string memberScope = "";
  if( member.DeclaringType != null )
    memberScope = GetMemberFullName( member.DeclaringType );
  else if( member is Type )
    memberScope = ((Type)member).Namespace;

  return memberScope + "." + member.Name;
}

Example use

Type type = typeof( string );

var file = GetXmlDocFile( type.Assembly );
var docXml = XDocument.Load( file.FullName );
var docMembers = docXml.Root.Element( "members" );

var member = type.GetProperty( "Length" );
var docMember = GetDocMember( docMembers, member );
Emperor XLII
Note that this only supports simple members (i.e. fields and properties), and does not support method arguments.
Emperor XLII
+1  A: 

I maintain the Jolt.NET project on CodePlex and have implemented a feature that performs this very task. Please refer to the Jolt library for more information.

In essence, the library allows you to programatically locate and query an XML doc comments file for an assembly using the metadata types in System.Reflection (i.e. MethodInfo, PropertyInfo, etc...).

Steve Guidi