2013-10-25 225 views
4

我剛剛開始使用Roslyn,我想查找所有使用屬性名稱「OneToOne」註釋的屬性。我啓動了SyntaxVisualizer並能夠獲得對該節點的引用,但我想知道是否有一種更簡單的方法來實現這一點。這是我的:如何獲取具有某些屬性的所有屬性?

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")))) 

回答

5

那麼,我會去使用語義,而不是語法。喜歡的東西(把我的頭頂部):

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)); 
+0

我無法得到它使用確切的語法,我不得不CH ange last line to following:&& m.GetAttributes()。Any(a => a.AttributeClass.MetadataName == attSymbol.MetadataName)); – epitka

+0

:似乎當一個人得到「classSymbol」它不能被轉換爲「SourcePropertySymbol」來獲得該屬性的類型?我們是否從這裏走過語法節點來查找類型?我必須做以下事情來獲取屬性member.DeclaringSyntaxNodes.First()的類型名稱。ChildNodes()。OfType ()。First()。GetFirstToken()。Value; – epitka

+1

那麼,「SourcePropertySymbol」是一個內部類型,但你應該能夠向公衆「PropertySymbol」類型轉換並獲得屬性的「類型」。 –

3

我類似的任務的方法(我想重寫方法和屬性與特定的屬性飾)是找到屬性符號的所有用途,然後遍歷引用並獲得方法/屬性聲明語法:

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

我不得不寫一些擴展方法,使生活更輕鬆:

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

編譯時沒有FindSymbol? – epitka

+0

@epitka oops,完全忘了'FindSymbol'是擴展方法。爲答案添加了代碼。 –

+0

GlobalNamespace上的GetAllTypes也是擴展方法嗎? – epitka

相關問題