【问题标题】:How to get a list of all fields with a specified attribute?如何获取具有指定属性的所有字段的列表?
【发布时间】:2013-03-14 08:46:01
【问题描述】:

我正在尝试查找具有指定属性的字段。我尝试修改 FirstQuickFix 示例,因为我认为这可能是一个很好的起点。但是如果我运行代码,什么都不会发生。任何想法我的主要问题是什么?

在阅读了项目概述和演练文档后,我的理解是,我能够请求令牌的属性,这是我在语法树中找到的。语法树是源代码的精确树表示。字段声明及其属性的连接可通过语义访问。还是我的理解完全错误?

[ExportCodeIssueProvider("FirstQuickFix_", LanguageNames.CSharp)]
class CodeIssueProvider : ICodeIssueProvider
{
    public IEnumerable<CodeIssue> GetIssues
      (IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
    {
        var tokens = from nodeOrToken in node.ChildNodesAndTokens()
                     where nodeOrToken.HasAnnotations(Type.GetType("myAttribute"))
                     select nodeOrToken.AsToken();

        foreach (var token in tokens)
        {
            var issueDescription = string.Format("found!!!");
            yield return new CodeIssue(CodeIssueKind.Info, token.Span, issueDescription);
        }
    }
}

编辑:

我想要实现的,就是找到ie。所有具有 myAttribute 属性的字段:

namespace ConsoleApplication
{
    class Program
    {
        [myAttribute]
        string myField = "test";

        public void testing()
        {
            Console.WriteLine(myField);
        }
    }
}

【问题讨论】:

  • 我认为您混淆了注释和属性。注释是 Roslyn 的一个特性,可以用来标记语法树中的一些节点。它们与属性无关。
  • @svick 谢谢这是一个很好的提示,但是我如何访问或查找具有指定属性的所有字段?我将添加一个示例,我试图找到我的问题。

标签: c# attributes field roslyn


【解决方案1】:

为此,您可以使用 LINQ 获取所有具有指定名称的 AttributeSyntax 节点,然后使用 Parent(两次)获取表示该字段的节点:

var fields = root.DescendantNodes()
                 .OfType<AttributeSyntax>()
                 .Where(a => a.Name.ToString() == "myAttribute")
                 .Select(a => a.Parent.Parent)
                 .Cast<FieldDeclarationSyntax>();

这是最原始的版本,仅适用于语法级别,因此如果您在另一个命名空间中有同名的属性,则使用该属性的全名(包括命名空间)或如果您使用using 来使用别名来引用属性类型。

如果你想支持它,你需要获取语义模型,然后获取表示属性类型的符号。

【讨论】:

  • 感谢@svick,到目前为止应该足够了,但我只是从fields 变量中得到了整个字符串privat int myField = 0;...我没有看到任何对象方法或属性,这可以帮助我。但我确信必须有机会访问这些信息。还是我必须走语义的方式?因为我只需要字段名称......当然有不同的快速和肮脏的解决方案来获取字段名称,但我更喜欢一个好的解决方案。谢谢!
  • @Anton 您没有在该变量中获得string,而是获得了FieldDeclarationSyntaxes 的集合,这应该正是您获得所需信息所需要的。
  • 非常感谢!我尝试使用 foreach 循环访问集合的条目,并且没有为变量提供特定类型而只使用了 var,因此 Visual Studio 没有为我提供此 FieldDeclarationSyntax 的正确属性和方法;-)
【解决方案2】:

对于您提供的已编辑示例,您可以将 LINQ 查询与 Type.GetField 方法结合使用:

using System.Collections.Generic;
using System.Linq;

class TestAttribute : System.Attribute { }

class State
{
    [Test] string name;
    [Test] string address;
    [Test] public string name2;
    [Test] public string address2;
    float height;
    public State(string name_, string address_, float height_)
    {
        name = name_;
        address = address_;
        height = height_;
        name2 = name_ + "2";
        address2 = address_ + "2";
    }
}

public class Program
{
    static void ShowFields<T>(IEnumerable<T> fieldList)
    {
        foreach (var field in fieldList)
        {
            System.Console.WriteLine(field.ToString());
        }
    }

    public static void Main(string[] args)
    {            
        State s = new State("Bob", "221 B Baker Street", 5.4f);
        System.Type stateType = typeof(State);
        System.Reflection.FieldInfo[] publicFieldList = stateType.GetFields();
        System.Console.WriteLine("----all public fields----");
        ShowFields(publicFieldList);

        System.Console.WriteLine("----all non public or instance fields----");
        System.Reflection.FieldInfo[] nonPublicFieldList;
        nonPublicFieldList = stateType.GetFields(System.Reflection.BindingFlags.NonPublic| System.Reflection.BindingFlags.Instance);
        ShowFields(nonPublicFieldList);

        var customAttributeFieldList = from t in stateType.GetFields()
        where t.GetCustomAttributes(false).Any(a => a is TestAttribute)
        select t;
        System.Console.WriteLine("----only public fields marked with a particular custom attribute----");
        ShowFields(customAttributeFieldList);
    }
}

【讨论】:

    【解决方案3】:

    这是工作代码示例,用于迭代类中具有自定义属性的属性。 您可以将此提示用于“如何获取具有指定属性的所有字段的列表?”。

    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
    
            var type = myClass.GetType();
    
            foreach (var property in type.GetProperties())
            {
                //Get ALL custom attributes of the property
                var propattr = property.GetCustomAttributes(false);
    
                //Get MyAttribute Attribute of the Property
                object attr =
                    (from row in propattr
                     where row.GetType() == typeof(MyAttribute)
                     select row).FirstOrDefault();
                if (attr == null || !(attr is MyAttribute))
                    continue;
    
                var myAttribute = attr as MyAttribute;
    
                //output: NameAttrValue and AgeAttrValue 
                Console.WriteLine(myAttribute.Val);
    
                //Output: Name and Age
                Console.WriteLine(property.Name);
            }
        }
    }
    
    public class MyClass
    {
        [My("NameAttrValue")]
        public string Name { get; set; }
    
        [My("AgeAttrValue")]
        public int Age { get; set; }
    
    
        public MyClass()
        {
            this.Name = "Jac";
            this.Age = 27;
        }
    }
    
    public class MyAttribute : Attribute
    {
        public MyAttribute(string val)
        {
            this.Val = val;
        }
    
        public string Val { get; set; }
    }
    

    【讨论】:

    • 但是我有点困惑,是否可以将这个示例集成到我的代码中?我的主要问题是,我以前从未使用过属性和 roslyn。如何在 Roslyn 中获取类的 n 个实例?我必须通过文档或节点走一条路吗?我觉得实现我想要的真的很容易,但是我没有得到它,对不起!
    • @Anton:我不确定你的上下文,我也不熟悉 Roslyn。我试图回答你问题的第二部分“我想要实现的目标是找到即所有具有myAttribute属性的字段:”
    • @jacobaloysious 除了类型不是来自已编译的程序集外,它来自 Roslyn 语法树。而且你不能为此使用反射。
    • @svick:我不确定 Roslyn 数据结构/对象。我试图举一个例子来获取属性的自定义属性,仅此而已。
    • @jacobaloysious 我的意思是这不是问题所在,所以你的回答在这里毫无用处。
    猜你喜欢
    • 1970-01-01
    • 2014-06-09
    • 2011-01-17
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    • 2020-07-21
    相关资源
    最近更新 更多