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:
<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?
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.
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 );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With