How to get all properties that are anotated with some attribute?

倾然丶 夕夏残阳落幕 提交于 2019-12-07 09:50:36

问题


I am just starting with Roslyn, and I want to find all properties that are annotated with attribute names "OneToOne". I fired up SyntaxVisualizer and was able to get reference to that node, but I am wondering is there a simpler way to achieve this. This is what I have:

var prop = document.GetSyntaxRoot()
             .DescendantNodes()
             .OfType<PropertyDeclarationSyntax>()
             .Where(p => p.DescendantNodes()
                 .OfType<AttributeSyntax>()
                 .Any(a => a.DescendantNodes()
                     .OfType<IdentifierNameSyntax>()
                     .Any(i => i.DescendantTokens()
                         .Any(dt => dt.Kind == SyntaxKind.IdentifierToken
                                 && dt.ValueText == "OneToOne"))))

回答1:


Well, I would go about this using Semantics, not Syntax. Something like (off the top of my head):

var attributeSymbol = compilation.GetTypeByMetadataName("ConsoleApplication1.OneToOneAttribute");
var propertySymbol = compilation.GetTypeByMetadataName("ConsoleApplication1.Program")
                     .GetMembers()
                     .Where(m => 
                            m.Kind == CommonSymbolKind.Property && 
                            m.GetAttributes().Any(a => a.AttributeClass.MetadataName == attributeSymbol.MetadataName));



回答2:


My approach for similar task (I wanted to rewrite methods and properties decorated with specific attribute) was to find all usages of the attribute symbol and then iterate over references and get method/property declaration syntax:

var attributeSymbol = compilation.FindSymbol(typeof(<Your attribute type>));
var references = attributeSymbol.FindReferences(solution);

foreach (ReferencedSymbol referencedSymbol in references)
{
    foreach (ReferenceLocation location in referencedSymbol.Locations)
    {
        var propertyDeclaration = location.Document.GetSyntaxRoot()
            .FindToken(location.Location.SourceSpan.Start)
            .Parent
            .FirstAncestorOrSelf<PropertyDeclarationSyntax>();
    }
}

I had to write few extension methods to make life easier:

public static class CompilationExtensions
{
    public static INamedTypeSymbol FindSymbol(this CommonCompilation compilation, Type searchedType)
    {
        var splitFullName = searchedType.FullName.Split('.');
        var namespaceNames = splitFullName.Take(splitFullName.Length - 1).ToArray();
        var className = splitFullName.Last();

        if (namespaceNames.Length == 0)
            return compilation.GlobalNamespace.GetAllTypes(new CancellationToken()).First(n => n.Name == className);

        var namespaces = compilation.GlobalNamespace.GetNamespaceMembers();
        INamespaceSymbol namespaceContainingType = null;
        foreach (var name in namespaceNames)
        {
            namespaceContainingType = namespaces.First(n => n.Name == name);
            namespaces = namespaceContainingType.GetNamespaceMembers();
        }

        return namespaceContainingType.GetAllTypes(new CancellationToken()).First(n => n.Name == className);
    }
}

public static class INamespaceSymbolExtension
{
    public static IEnumerable<INamedTypeSymbol> GetAllTypes(this INamespaceSymbol @namespace, CancellationToken cancellationToken)
    {
        Queue<INamespaceOrTypeSymbol> symbols = new Queue<INamespaceOrTypeSymbol>();
        symbols.Enqueue(@namespace);

        while (symbols.Count > 0)
        {
            cancellationToken.ThrowIfCancellationRequested();

            INamespaceOrTypeSymbol namespaceOrTypeSymbol = symbols.Dequeue();
            INamespaceSymbol namespaceSymbol = namespaceOrTypeSymbol as INamespaceSymbol;
            if (namespaceSymbol == null)
            {
                INamedTypeSymbol typeSymbol = (INamedTypeSymbol) namespaceOrTypeSymbol;
                Array.ForEach(typeSymbol.GetTypeMembers().ToArray(), symbols.Enqueue);

                yield return typeSymbol;
            }
            else
            {
                Array.ForEach(namespaceSymbol.GetMembers().ToArray(), symbols.Enqueue);
            }
        }
    }
}


来源:https://stackoverflow.com/questions/19594847/how-to-get-all-properties-that-are-anotated-with-some-attribute

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!