C# Reflection : Finding Attributes on a Member Fie

2019-01-24 02:19发布

问题:

I may be asking this incorrectly, but can/how can you find fields on a class within itself... for example...

public class HtmlPart {
  public void Render() {
    //this.GetType().GetCustomAttributes(typeof(OptionalAttribute), false);
  }
}

public class HtmlForm {
  private HtmlPart _FirstPart = new HtmlPart();      
  [Optional] //<-- how do I find that?
  private HtmlPart _SecondPart = new HtmlPart();
}

Or maybe I'm just doing this incorrectly... How can I call a method and then check for attributes applied to itself?

Also, for the sake of the question - I'm just curious if it was possible to find attribute information without knowing/accessing the parent class!

回答1:

If I understand your question correctly, I think what you are trying to do is not possible...

In the Render method, you want to get a possible attribute applied to the object. The attribute belongs to the field _SecondPart witch belongs to the class HtmlForm.

For that to work you would have to pass the calling object to the Render method:

    public class HtmlPart {
        public void Render(object obj) {
            FieldInfo[] infos = obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

            foreach (var fi in infos)
            {
                if (fi.GetValue(obj) == this && fi.IsDefined(typeof(OptionalAttribute), true))
                    Console.WriteLine("Optional is Defined");
            }
        }
    }


回答2:

Here's an example of given a single object how to find if any public or private fields on that object have a specific property:

var type = typeof(MyObject);
foreach (var field in type.GetFields(BindingFlags.Public |
             BindingFlags.NonPublic | BindingFlags.Instance))
{
    if (field.IsDefined(typeof(ObsoleteAttribute), true))
    {
        Console.WriteLine(field.Name);
    }

}

For the second part of your question you can check if an attribute is defiend on the current method using:

MethodInfo.GetCurrentMethod().IsDefined(typeof(ObsoleteAttribute));

Edit

To answer your edit yes it is possible without knowing the actual type. The following function takes a type Parameter and returns all fields which have a given attribute. Someone somewhere is going to either know the Type you want to search, or will have an instance of the type you want to search.

Without that you'd have to do as Jon Skeet said which is to enumerate over all objects in an assembly.

   public List<FieldInfo> FindFields(Type type, Type attribute)
    {
        var fields = new List<FieldInfo>();
        foreach (var field in type.GetFields(BindingFlags.Public |
                           BindingFlags.NonPublic |
                           BindingFlags.Instance))
        {
            if (field.IsDefined(attribute, true))
            {
                fields.Add(field);
            }

        }
        return fields;
    }


回答3:

You can find fields within a class using Type.GetFields, and you can find attributes applied to a field using MemberInfo.GetCustomAttributes or IsDefined - but if you need to find all the fields of a particular type, you're going to have to:

  • Iterate over all the assemblies you want to search
  • Iterate over all the types within each assembly
  • Iterate over all the fields within each type
  • Check for the attribute's presence/absence for each field

Now, if you're really trying to find out "is a particular attribute applied to a field whose value is a reference to 'this' object" then that's even harder - because you'd have to know all about every object in the system. You should also bear in mind that there could be two fields both with the same value, i.e. referencing the same object. Would the object count as "optional" in that case or not?

Basically, if the object should have a property (e.g. optional or not) then that must be a property of the object itself, not the field containing the property.

It could be that I'm misinterpreting what you're trying to do, but I suspect it's either not feasible or at least not a good idea. Could you explain the bigger picture here? What are you really trying to achieve with this attribute?