从 MetadataReference 获取 ISymbol 的文档

Jiř*_*nec 5 c# analysis roslyn roslyn-code-analysis

我最近开始学习 Roslyn 代码分析。我浏览了提供的示例代码。我的问题如下:

有没有办法获取从引用库加载的符号的 XML 文档注释?

我使用的示例代码是FAQ(7). 目标是获得函数的文档注释Console.Write。

    public void GetWriteXmlComment()
    {
        var project1Id = ProjectId.CreateNewId();
        var document1Id = DocumentId.CreateNewId(project1Id);

        var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);

        var solution = new AdhocWorkspace().CurrentSolution
            .AddProject(project1Id, "Project1", "Project1", LanguageNames.CSharp)
            .AddMetadataReference(project1Id, mscorlib);

        var declarations = SymbolFinder.FindDeclarationsAsync(solution.Projects.First(), "Write", true).Result;

        var decFirst = declarations.First();
        var commentXml = decFirst.GetDocumentationCommentXml();
    }
Run Code Online (Sandbox Code Playgroud)

示例代码适用于某些方法 - 它获取文档文本。但对于诸如 之类的方法Console.Write,它使用NullDocumentationProvider并因此返回空字符串。

更新

我发现我可以加载MetadataReference实例TestDocumentationProvider如下:

        var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location,
            default(MetadataReferenceProperties), new TestDocumentationProvider());
Run Code Online (Sandbox Code Playgroud)

其中TestDocumentationProvider实现Microsoft.CodeAnalysis DocumentationProvider抽象类。

    private class TestDocumentationProvider : DocumentationProvider
    {
        protected override string GetDocumentationForSymbol(string documentationMemberID, CultureInfo preferredCulture, CancellationToken cancellationToken = default(CancellationToken))
        {
            // To-Be-Done
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在问题缩小到如何使用documentationMemberID?阅读文档

Eli*_*bel 3

更新:在Roslyn 2.0 中您可以使用XmlDocumentationProvider.CreateFromFile。


我能想到的唯一方法是使用 Reflection 来创建FileBasedXmlDocumentationProvider(或者从 GitHub 复制其实现)。您还需要搜索参考程序集,因为框架程序集的加载位置不包含文档。

private static MetadataReference FromType(Type type)
{
    var path = type.Assembly.Location;
    return MetadataReference.CreateFromFile(path, documentation: GetDocumentationProvider(path));
}

private static string GetReferenceAssembliesPath()
{
    var programFiles =
        Environment.GetFolderPath(Environment.Is64BitOperatingSystem
            ? Environment.SpecialFolder.ProgramFilesX86
            : Environment.SpecialFolder.ProgramFiles);
    var path = Path.Combine(programFiles, @"Reference Assemblies\Microsoft\Framework\.NETFramework");
    if (Directory.Exists(path))
    {
        var directories = Directory.EnumerateDirectories(path).OrderByDescending(Path.GetFileName);
        return directories.FirstOrDefault();
    }
    return null;
}

private static DocumentationProvider GetDocumentationProvider(string location)
{
    var referenceLocation = Path.ChangeExtension(location, "xml");
    if (File.Exists(referenceLocation))
    {
        return GetXmlDocumentationProvider(referenceLocation);
    }
    var referenceAssembliesPath = GetReferenceAssembliesPath();
    if (referenceAssembliesPath != null)
    {
        var fileName = Path.GetFileName(location);
        referenceLocation = Path.ChangeExtension(Path.Combine(referenceAssembliesPath, fileName), "xml");
        if (File.Exists(referenceLocation))
        {
            return GetXmlDocumentationProvider(referenceLocation);
        }
    }
    return null;
}

private static DocumentationProvider GetXmlDocumentationProvider(string location)
{
    return (DocumentationProvider)Activator.CreateInstance(Type.GetType(
        "Microsoft.CodeAnalysis.FileBasedXmlDocumentationProvider, Microsoft.CodeAnalysis.Workspaces.Desktop"),
        location);
}
Run Code Online (Sandbox Code Playgroud)

我在RoslynPad中使用过类似的东西。