使用 Roslyn 获取项目中引用类型的列表 [英] Get a list of referenced Types within a project with Roslyn

查看:61
本文介绍了使用 Roslyn 获取项目中引用类型的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to get a list of all used types in a project, for example:

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

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

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

What I have is freaking slow... for each file (syntax tree), I do the following:

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 框架).

I am making a tool that analyses a project, and tells what .Net framework versions support the given project (e.g. Portable .Net Frameworks).

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

I hoped it would be faster to match a set of used types with a set of available types from the framework, before compiling.

对于小文件,此代码足够快,并且总时间少于使用所有可能的框架进行编译的时间……但是对于大文件,这是不可接受的.

With small files this code is fast enough, and the total amount of time is less than that of compiling with every possible framework... but with a large files it is unacceptable.

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

Is there a way to get the list of types in a way that is acceptable?

推荐答案

所以,我吸取了教训:永远不要假设一个不可变的结构会缓存它的任何计算仅仅因为两个调用将返回相同的结果.

So, I've learnt a lesson: never assume that an immutable structure is going to cache any of it's calculations just because two calls would return the same result.

确实,当方法是纯方法时,返回的结构总是相同的,但不必是相同的实例.

It is true that when the method is pure, the return is always the same structurally, but it doesn't have to be the same instance.

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

My assumption lead me to an error: thinking that this.compilation.GetSemanticModel(id.SyntaxTree) would always return the same instance of the semantic model for a given SyntaxTree... it's not true.

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

I changed my code to the following, and now it is blazing fast:

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);
}

这篇关于使用 Roslyn 获取项目中引用类型的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆