c# - 使用 Roslyn 获取项目中引用类型的列表

标签 c# roslyn

我想获取项目中所有使用类型的列表,例如:

var x = 1;
var y = x.ToString().GetType();

代码应返回System.Int32System.StringSystem.Type

我的速度非常慢...对于每个文件(语法树),我执行以下操作:

var root = await syntaxTree.GetRootAsync();
var nodes = root.DescendantNodes(n => true);

if (nodes != null)
{
    var syntaxNodes = nodes as SyntaxNode[] ?? nodes.ToArray();

    // IdentifierNameSyntax:
    //  - var keyword
    //  - identifiers of any kind (including type names)
    var namedTypes = syntaxNodes
        .OfType<IdentifierNameSyntax>()
        .Select(id => this.compilation
                  .GetSemanticModel(id.SyntaxTree)
                  .GetSymbolInfo(id)
                  .Symbol)
        .OfType<INamedTypeSymbol>()
        .ToArray();

    // add the found types to the list
    this.AddRange(namedTypes);

    // ExpressionSyntax:
    //  - method calls
    //  - property uses
    //  - field uses
    //  - all kinds of composite expressions
    var expressionSyntaxs = syntaxNodes
        .OfType<ExpressionSyntax>()
        .ToList();

    var typeSymbols = new List<ITypeSymbol>();
    for (int index = 0; index < expressionSyntaxs.Count; index++)
    {
        ExpressionSyntax ma = expressionSyntaxs[index];
        typeSymbols.Add(this.compilation
                    .GetSemanticModel(ma.SyntaxTree)
                    .GetTypeInfo(ma)
                    .Type);
    }

    var expressionTypes = typeSymbols
        .OfType<INamedTypeSymbol>()
        .ToArray();

    // add the found types to the list
    this.AddRange(expressionTypes);
}

动机:

我正在制作一个分析项目的工具,并告知哪些 .Net 框架版本支持给定项目(例如可移植 .Net 框架)。

我希望在编译之前将一组使用过的类型与框架中的一组可用类型匹配会更快。

对于小文件,此代码足够快,并且总时间少于使用每个可能的框架进行编译的时间......但是对于大文件,这是 Not Acceptable 。

有没有办法以可接受的方式获取类型列表?

最佳答案

因此,我吸取了教训:永远不要假设不可变结构会缓存它的任何计算,只是因为两次调用会返回相同的结果。

的确,当方法是纯方法时,返回在结构上总是相同的,但不一定是相同的实例。

我的假设导致我犯了一个错误:认为 this.compilation.GetSemanticModel(id.SyntaxTree) 总是会为给定的 SyntaxTree 返回相同的语义模型实例>...这不是真的。

我将我的代码更改为以下内容,现在速度非常快:

var root = await syntaxTree.GetRootAsync();
var nodes = root.DescendantNodes(n => true);

var st = root.SyntaxTree;
var sm = this.compilation.GetSemanticModel(st);

if (nodes != null)
{
    var syntaxNodes = nodes as SyntaxNode[] ?? nodes.ToArray();

    // IdentifierNameSyntax:
    //  - var keyword
    //  - identifiers of any kind (including type names)
    var namedTypes = syntaxNodes
        .OfType<IdentifierNameSyntax>()
        .Select(id => sm.GetSymbolInfo(id).Symbol)
        .OfType<INamedTypeSymbol>()
        .ToArray();

    this.Add(namedTypes);

    // ExpressionSyntax:
    //  - method calls
    //  - property uses
    //  - field uses
    //  - all kinds of composite expressions
    var expressionTypes = syntaxNodes
        .OfType<ExpressionSyntax>()
        .Select(ma => sm.GetTypeInfo(ma).Type)
        .OfType<INamedTypeSymbol>()
        .ToArray();

    this.Add(expressionTypes);
}

关于c# - 使用 Roslyn 获取项目中引用类型的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29176579/

相关文章:

c# - 将引用 C++/CLI 包装器的 UserControl 添加到表单的非托管 dll 时出现问题

c# - 如何在 Visual Studio 2017 中禁用 Roslyn 语言服务?

typescript - 是否有用于 TypeScript 的代码生成 API?

.net - 如何告诉 Roslyn C# 编译器使用特定版本的 .NET?

c# - 请求限制是否以 BITS/BYTES 为单位?

C# 这个初始化程序真的是多余的吗?

c# - 为 C# 中的每个表达式向 lambda 添加条件

c# - 在游戏/程序运行时创建覆盖屏幕?

c# - 如何使用 Roslyn 验证特定 Actor 阵容是否有效

c# - 有没有办法为 "r and "加载命令设置工作目录