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

3 回答 3

6

好吧,我会使用语义而不是语法来解决这个问题。像(在我的脑海中):

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));
于 2013-10-25T16:58:31.373 回答
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);
            }
        }
    }
}
于 2013-10-26T10:28:56.097 回答
1

这是我的帮助类,它可以找到所有属性、类名和类命名空间

public class CsharpClass
{
    public string Name { get; set; }

    public string Namespace { get; set; }

    public List<CsharpProperty> Properties { get; set; }

    public string PrimaryKeyType { get; set; }

    public class CsharpProperty
    {
        public string Name { get; set; }
        public string Type { get; set; }

        public CsharpProperty(string name, string type)
        {
            Name = name;
            Type = type;
        }
    }

    public CsharpClass()
    {
        Properties = new List<CsharpProperty>();
    }
}

public static class CsharpClassParser
{
    public static CsharpClass Parse(string content)
    {
        var cls = new CsharpClass();
        var tree = CSharpSyntaxTree.ParseText(content);
        var members = tree.GetRoot().DescendantNodes().OfType<MemberDeclarationSyntax>();

        foreach (var member in members)
        {
            if (member is PropertyDeclarationSyntax property)
            {
                cls.Properties.Add(new CsharpClass.CsharpProperty(
                     property.Identifier.ValueText,
                     property.Type.ToString())
                 );
            }

            if (member is NamespaceDeclarationSyntax namespaceDeclaration)
            {
                cls.Namespace = namespaceDeclaration.Name.ToString();
            }

            if (member is ClassDeclarationSyntax classDeclaration)
            {
                cls.Name = classDeclaration.Identifier.ValueText;

                cls.PrimaryKeyType = FindPrimaryKeyType(classDeclaration);
            }

            //if (member is MethodDeclarationSyntax method)
            //{
            //    Console.WriteLine("Method: " + method.Identifier.ValueText);
            //}
        }


        return cls;
    }

    private static string FindPrimaryKeyType(ClassDeclarationSyntax classDeclaration)
    {
        if (classDeclaration == null)
        {
            return null;
        }

        if (classDeclaration.BaseList == null)
        {
            return null;
        }

        foreach (var baseClass in classDeclaration.BaseList.Types)
        {
            var match = Regex.Match(baseClass.Type.ToString(), @"<(.*?)>");
            if (match.Success)
            {
                var primaryKey = match.Groups[1].Value;

                if (AppConsts.PrimaryKeyTypes.Any(x => x.Value == primaryKey))
                {
                    return primaryKey;
                }
            }
        }

        return null;
    }
}

用法:

const string content = @"
namespace Acme.Airlines.AirCraft
{
    public class AirCraft
    {
        public virtual string Name { get; set; }

        public virtual int Code { get; set; }

        public AirCraft()
        {

        }
    }
}";

var csharpClass = CsharpClassParser.Parse(content);

Console.WriteLine(csharpClass.Name);
Console.WriteLine(csharpClass.Namespace);
Console.WriteLine(csharpClass.Properties.Count);
于 2020-04-28T19:40:14.937 回答