简体   繁体   English

使用 Roslyn 从属性中获取类型

[英]Get type from property with Roslyn

Using Roslyn I'm trying to interpret some code that looks something like this:使用 Roslyn 我试图解释一些看起来像这样的代码:

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

What I would like to do is get MyBar and then get that type as a symbol, but I'm not sure if this is even something that is possible or practical to do.我想做的是获取MyBar然后将该类型作为符号获取,但我不确定这是否可行或可行。 I'm going to have several classes that look like this and all derive from a base class.我将有几个看起来像这样的类,它们都派生自一个基类。

Given the ClassDeclarationSyntax for Foo , I can do this:鉴于FooClassDeclarationSyntax ,我可以这样做:

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

Or given the INamedTypeSymbol for Foo , I can do this:或者给定FooINamedTypeSymbol ,我可以这样做:

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

But I don't know where to go from there.但我不知道从那里去哪里。

Ultimately I want to be able to get the symbol for MyBar for further analysis, so maybe even getting the string "MyBar" isn't going to help because it's not fully qualified.最终,我希望能够获得MyBar的符号以进行进一步分析,因此即使获得字符串"MyBar"也无济于事,因为它不完全合格。

Any suggestions?有什么建议么?

EDIT :编辑

I'm getting a project and a compilation like this:我得到一个项目和这样的汇编:

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

compilation is a CSharpCompilation here. compilation是这里的CSharpCompilation From there I do something like this:从那里我做这样的事情:

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...
    }
}

Either way I get model I end up with a SyntaxTreeSemanticModel which doesn't seem to have a GetTypeSymbol method.无论哪种方式,我得到的model我结束了一个SyntaxTreeSemanticModel这似乎不具有GetTypeSymbol方法。

You need the Semantic Model, which comes from a Compilation (with references & configuration).您需要语义模型,它来自Compilation (带有参考和配置)。

You can then call GetTypeSymbol() GetSymbolInfo() on that node and cast to INamedTypeSymbol .然后,您可以在该节点上调用 GetTypeSymbol() GetSymbolInfo()并转换为INamedTypeSymbol

You should look for the ReturnStatementSyntax and TypeOfExpressionSyntax .您应该寻找ReturnStatementSyntaxTypeOfExpressionSyntax This contains the type MyBar .这包含类型MyBar With the SemanticModel you can get the SymbolInfo like this:使用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;
            }
        }
    }
}

You can also use a SyntaxWalker for this:您还可以为此使用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 );
    }
}

Usage:用法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM