简体   繁体   中英

C# - Enumerating Custom Attributes via Reflection

Here is my attribute definition:

[AttributeUsage(AttributeTargets.Field)]
public class Optional : System.Attribute
{
    public Optional()
    {
    }
}

In MyClass:

[Optional] public TextBox Name;

Finally in another function:

typeof(MyClass).GetFields().ToList<FieldInfo>().ForEach(x => writer.WriteLine(
   x.FieldType + " is called " + 
   x.Name + " and has attributes " + 
   x.GetCustomAttributes(true)[0]
 ));

The problem is I get an error for index 0. I just want to check for fields where the attribute is applied. The error goes away when I remove x.GetCustomAttributes(true)[0] .

Exact Error:

Exception Details: System.IndexOutOfRangeException: Index was outside the bounds of the array.

Source Error:

Line 63:             }
Line 64: 
Line 65:             typeof(T).GetFields().ToList<FieldInfo>().ForEach(x => writer.WriteLine(x.FieldType + " is called " + 
Line 66:                 x.Name + " and has attributes " + 
Line 67:                 x.GetCustomAttributes(true)[0]+ "</br>"));

Seems like there might be two questions here. To find all the fields that have your [Optional] attribute, you want:

typeof(MyClass).GetFields().Where(
   f => f.GetCustomAttributes(typeof(OptionalAttribute), true).Any())

To write out the custom attributes on all your fields, you want:

typeof(MyClass).ToList<FieldInfo>().ForEach(x => 
{
 writer.WriteLine(
   x.FieldType + " is called " + 
   x.Name + " and has attributes " + 
   string.Join(", ", x.GetCustomAttributes(true).Select(a => a.ToString()).ToArray()));
});

As you seem to have gathered, you are getting this error because you are trying to get the 0th element of an empty array, which is of course illegal. You need to filter out the fields without any attributes first, like so:

var fields = from fieldInfo in typeof(MyClass).GetFields()
             let Attributes = fieldInfo.GetCustomAttributes(true)
             where Attributes.Any()
             select new { fieldInfo.FieldType, fieldInfo.Name, Attributes };

foreach (var field in fields)
{
    writer.WriteLine(field.FieldType + " is called " +
                     field.Name + " and its first attribute is " +
                     field.Attributes.First());
}

If you are specifically interested in those with OptionalAttribute , then you are probably looking for something like this instead:

var fields = from fieldInfo in typeof(MyClass).GetFields()
             let attributes = fieldInfo.GetCustomAttributes(true).OfType<OptionalAttribute>()
             where attributes.Any()
             select new { fieldInfo.FieldType, fieldInfo.Name, Attribute = attributes.Single() };

foreach (var field in fields)
{
    writer.WriteLine(field.FieldType + " is called " +
                     field.Name + " and its OptionalAttribute is " +
                     field.Attribute);
}

Check the attribute existence like this:

x.GetCustomAttributes(true).Any(item => item is OptionalAttribute)

I have assumed that you will rename your Optional attribute to OptionalAttribute as all attributes should have the "Attribute" suffix.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM