【问题标题】:Get type from property with Roslyn使用 Roslyn 从属性中获取类型
【发布时间】:2019-11-23 22:06:12
【问题描述】:

使用 Roslyn,我试图解释一些看起来像这样的代码:

public class Foo
{
    public override Type BarType
    {
        get { return typeof(MyBar); }
    }
}

我想做的是获取MyBar,然后获取该类型作为符号,但我不确定这是否可行或实际可行。我将有几个看起来像这样的类,它们都派生自一个基类。

鉴于FooClassDeclarationSyntax,我可以这样做:

var prop = syntax.DescendantNodes().OfType<PropertyDeclarationSyntax>()
              .FirstOrDefault(p => p.Identifier.ToString() == "BarType");

或者给定INamedTypeSymbol for Foo,我可以这样做:

var member = symbol.GetMembers("BarType").FirstOrDefault();

但我不知道从那里去哪里。

最终我希望能够获得MyBar 的符号以进行进一步分析,因此即使获得字符串"MyBar" 也无济于事,因为它不是完全合格的。

有什么建议吗?

编辑

我得到一个项目和一个像这样的编译:

var workspace = MSBuildWorkspace.Create();
var project = workspace.OpenProjectAsync(projectPath).Result;
var compilation = project.GetCompilationAsync().Result;

compilation 在这里是CSharpCompilation。从那里我做这样的事情:

foreach (var doc in project.Documents)
{
    Console.WriteLine($"Analyzing {doc.Name}");

    //var model = doc.GetSemanticModelAsync().Result;
    var tree = doc.GetSyntaxTreeAsync().Result;
    var root = tree.GetRoot();
    var model = compilation.GetSemanticModel(tree);
    var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();

    foreach (var syntax in classes)
    {
        var symbol = model.GetDeclaredSymbol(syntax);
        //... need to analyze properties in the class here...
    }
}

无论哪种方式,我都会得到model,我最终会得到一个SyntaxTreeSemanticModel,它似乎没有GetTypeSymbol 方法。

【问题讨论】:

    标签: c# roslyn


    【解决方案1】:

    您应该寻找ReturnStatementSyntaxTypeOfExpressionSyntax。这包含MyBar 类型。使用SemanticModel,您可以像这样获得SymbolInfo

    var classDeclarationSyntaxs = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
    foreach ( var classDeclarationSyntax in classDeclarationSyntaxs )
    {
        var propertyDeclarationSyntaxs = classDeclarationSyntax.Members.OfType<PropertyDeclarationSyntax>();
        var barTypePropertyDeclarationSyntax = propertyDeclarationSyntaxs.FirstOrDefault( p => p.Identifier.Text == "BarType" );
        if ( barTypePropertyDeclarationSyntax != null )
        {
            var returnStatementSyntax = barTypePropertyDeclarationSyntax.DescendantNodes().OfType<ReturnStatementSyntax>().FirstOrDefault();
            if ( returnStatementSyntax != null )
            {
                var typeOfExpressionSyntax = returnStatementSyntax.ChildNodes().OfType<TypeOfExpressionSyntax>().FirstOrDefault();
                if ( typeOfExpressionSyntax != null )
                {
                    var symbolInfo = semanticModel.GetSymbolInfo( typeOfExpressionSyntax.Type );
                    var symbolInfoSymbol = symbolInfo.Symbol;
                }
            }
        }
    }
    

    您也可以为此使用SyntaxWalker

    public class TypeOfSyntaxWalker : CSharpSyntaxWalker
    {
        private readonly SemanticModel _semanticModel;
    
        public ISymbol SymbolInfoSymbol { get; private set; }
    
        public TypeOfSyntaxWalker( SemanticModel semanticModel )
        {
            _semanticModel = semanticModel;
        }
    
        public override void VisitTypeOfExpression( TypeOfExpressionSyntax typeOfExpressionSyntax )
        {
            var parent = typeOfExpressionSyntax.Parent;
            if ( parent.Kind() == SyntaxKind.ReturnStatement )
            {
                var propertyDeclarationSyntax = parent.FirstAncestorOrSelf<PropertyDeclarationSyntax>();
                if ( propertyDeclarationSyntax != null &&
                        propertyDeclarationSyntax.Identifier.ValueText == "BarType" )
                {
                    var symbolInfo = _semanticModel.GetSymbolInfo( typeOfExpressionSyntax.Type );
                    SymbolInfoSymbol = symbolInfo.Symbol;
                }
            }
            base.VisitTypeOfExpression( typeOfExpressionSyntax );
        }
    }
    

    用法:

    var classDeclarationSyntaxs = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
    foreach ( var classDeclarationSyntax in classDeclarationSyntaxs )
    {
        var typeOfSyntaxWalker = new TypeOfSyntaxWalker( semanticModel );
        typeOfSyntaxWalker.VisitClassDeclaration( classDeclarationSyntax );
        var symbolInfoSymbol = typeOfSyntaxWalker.SymbolInfoSymbol;
    }
    

    【讨论】:

      【解决方案2】:

      您需要语义模型,它来自Compilation(带有引用和配置)。

      然后您可以在该节点上调用 GetTypeSymbol() GetSymbolInfo() 并转换为 INamedTypeSymbol

      【讨论】:

      • 您能详细说明一下吗?我在member 上找不到GetTypeSymbol
      • @MattBurland:该方法在SemanticModel 上,来自CompilationProject
      • 感谢您的帮助,但我仍然没有看到。我稍微编辑了这个问题,以包含更多我正在尝试做的事情。我从project.GetCompilationAsync().Result 得到一个编译,我可以从compilation.GetSemanticModel(tree) 得到一个SemanticModel,但生成的模型仍然没有GetTypeSymbol() 方法
      • @MattBurland:对不起;试试GetSymbolInfo()
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 2021-12-04
      相关资源
      最近更新 更多