如何比较 Roslyn 中不同项目的类型符号 (ITypeSymbol)? [英] How to compare type symbols (ITypeSymbol) from different projects in Roslyn?

查看:60
本文介绍了如何比较 Roslyn 中不同项目的类型符号 (ITypeSymbol)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在解决方案中有 2 个测试项目.
第一个项目(VDoc")声明 VDocQuery 类型.
第二个项目(VDocQueryTest")调用 VDocQuery 构造函数.
我得到 2 个 VDocQuery 的 ITypeSymbol(每个项目一个),比​​较它,但得到错误的结果.

I have 2 test projects in solution.
First project ("VDoc") declare VDocQuery type.
Second project ("VDocQueryTest" ) calls VDocQuery constructor.
I get 2 VDocQuery's ITypeSymbol's (one from each project), compare it, but get false result.

步骤:
1. 获取第一个 ITypeSymbol(来自 VDoc 项目,使用 SemanticModel.LookupNamespacesAndTypes() 方法).
2. 从 VDocQueryTest 项目中获取第二个 ITypeSymbol(来自 ObjectCreationExpressionSyntax.GetTypeInfo().Type)
3. 与 ITypeSymbol.Equals(ITypeSymbol) 进行比较.

Steps:
1. Get first ITypeSymbol (from VDoc project with SemanticModel.LookupNamespacesAndTypes() method).
2. Get second ITypeSymbol from VDocQueryTest project (from ObjectCreationExpressionSyntax.GetTypeInfo().Type)
3. Compare it with ITypeSymbol.Equals(ITypeSymbol).

我希望得到正确的结果,但得到了错误的结果.

I expected true result, but get false result.

问题:如何在一个解决方案中正确比较来自不同项目的 ITypeSymbols?

代码示例:

class Program
{
    static void Main(string[] args)
    {
        string solutionPath = @"..\..\..\StaticAnalysis.sln";

        MSBuildWorkspace workspace = MSBuildWorkspace.Create();
        Solution solution = workspace.OpenSolutionAsync(solutionPath).Result;

        var vdocProject = FindProjectByName("VDoc", solution);
        SemanticModel semanticModel = vdocProject.Documents.First().GetSemanticModelAsync().Result;
        var nsVDocQueryFunctionalTest = (INamespaceOrTypeSymbol)semanticModel.LookupNamespacesAndTypes(0, null, "VDocQueryFunctionalTest").First();
        var tVDocQuery = (ITypeSymbol)semanticModel.LookupNamespacesAndTypes(0, nsVDocQueryFunctionalTest, "VDocQuery").First();

        TypeInfo ti = GetFromVDocRef(solution);
        bool result1 = ti.Type.Equals(tVDocQuery); // false, expected = true?

        //these 2 lines added after Jason Malinowski answer
        var sVDocQuerySource = SymbolFinder.FindSourceDefinitionAsync(ti.Type, solution).Result;
        bool result2 = sVDocQuerySource.Equals(tVDocQuery); // false, expected = true?

       //this line solved the problem, thanks to @Tamas
       bool result3 = ti.Type.DeclaringSyntaxReferences.FirstOrDefault()?.Equals(tVDocQuery.DeclaringSyntaxReferences.FirstOrDefault()) ?? false;
    }

    private static TypeInfo GetFromVDocRef(Solution solution)
    {
        var vdocQueryTestProject = FindProjectByName("VDocQueryTest", solution);
        var vdocQueryTestProjectSemanticModel = vdocQueryTestProject.Documents.First().GetSemanticModelAsync().Result;
        var compilationUnit = (CompilationUnitSyntax)vdocQueryTestProject.Documents.First().GetSyntaxRootAsync().Result;
        var ns = (NamespaceDeclarationSyntax)compilationUnit.Members[0];
        var cls = (ClassDeclarationSyntax)ns.Members[0];
        var method = (MethodDeclarationSyntax)cls.Members[0];
        var stat = (ExpressionStatementSyntax)method.Body.Statements[0];
        var newExpr = (ObjectCreationExpressionSyntax)stat.Expression;
        var ti = vdocQueryTestProjectSemanticModel.GetTypeInfo(newExpr);
        return ti;
    }

    static Project FindProjectByName(string projectName, Solution solution)
    {
        var project = solution.Projects.SingleOrDefault(p => p.Name == projectName);
        return project;
    }
}

VDocQuery.cs:

VDocQuery.cs:

using System.Collections.Generic;

namespace VDocQueryFunctionalTest
{
    public class VDocQuery
    {
        public VDocQuery()
        {
        }

        public void AddFields(string docType, params string[] fields)
        {
        }

        public List<VDoc> Execute()
        {
            return null;
        }
    }
}

VDocQueryUse.cs:

VDocQueryUse.cs:

using VDocQueryFunctionalTest;

namespace VDocQueryTest
{
    static class VDocQueryUse
    {
        public static void VDocQueryUseTest()
        {
            new VDocQuery();
        }
    }
}

推荐答案

我可以通过在两个项目中使用不同的目标框架来重现您的问题.为两个项目设置相同的目标框架,然后您的原始解决方案将找到匹配的类型.

I could reproduce your problem by using different target frameworks in the two projects. Set the same target framework for both projects and then your original solution will find the matching types.

如果你不能改变目标框架,那么你仍然可以比较ITypeSymbol.DeclaringSyntaxReferences.

If you can't change the target frameworks, then you could still compare the ITypeSymbol.DeclaringSyntaxReferences.

这篇关于如何比较 Roslyn 中不同项目的类型符号 (ITypeSymbol)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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