2013-10-25 161 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

相关问题