С# Отражение: поиск атрибутов на поле члена

Возможно, я задаю это неправильно, но могу/как вы можете найти поля в классе внутри себя... например...

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();
}

Или, может быть, я просто делаю это неправильно... Как я могу вызвать метод, а затем проверить атрибуты, применяемые к себе?

Кроме того, ради вопроса - мне просто любопытно, можно ли находить информацию об атрибутах, не зная/получая доступ к родительскому классу!

Ответ 1

Если я правильно понимаю ваш вопрос, я думаю, что то, что вы пытаетесь сделать, невозможно...

В методе Render вы хотите получить возможный атрибут, применяемый к объекту. Атрибут принадлежит полю _SecondPart, который принадлежит классу HtmlForm.

Для этого вам нужно передать вызывающий объект методу Render:

    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

Здесь приведен пример одного объекта, как найти, имеют ли какие-либо общедоступные или частные поля на этом объекте определенное свойство:

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);
    }

}

Во второй части вашего вопроса вы можете проверить, существует ли атрибут для текущего метода, используя:

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

Edit

Чтобы ответить на ваше редактирование да, это возможно, не зная фактического типа. Следующая функция принимает параметр Param и возвращает все поля, которые имеют данный атрибут. Кто-то где-то будет знать тип, который вы хотите найти, или будет иметь экземпляр типа, который вы хотите найти.

Без этого вам придется сделать, как сказал Джон Скит, который должен перечислить все объекты в сборке.

   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

Вы можете найти поля в классе с помощью Type.GetFields, и вы можете найти атрибуты, применяемые к полю, используя MemberInfo.GetCustomAttributes или IsDefined - но если вам нужно найти все поля определенного типа, вы придется:

  • Итерации по всем узлам, которые вы хотите искать
  • Итерация по всем типам внутри каждой сборки
  • Итерации по всем полям в каждом типе
  • Проверить наличие/отсутствие атрибута для каждого поля

Теперь, если вы действительно пытаетесь выяснить, "это особый атрибут, применяемый к полю, значение которого является ссылкой на объект 'this'", то это еще сложнее - потому что вам нужно будет знать все о каждом объекте в системе. Вы также должны иметь в виду, что могут быть два поля с одинаковым значением, то есть ссылки на один и тот же объект. Будет ли объект считать "необязательным" в этом случае или нет?

В принципе, если объект должен иметь свойство (например, необязательное или нет), то это должно быть свойство самого объекта, а не поле, содержащее свойство.

Возможно, я неправильно интерпретирую то, что вы пытаетесь сделать, но я подозреваю, что это либо невозможно, либо, по крайней мере, не очень хорошая идея. Не могли бы вы объяснить здесь большую картину? Что вы действительно пытаетесь достичь с помощью этого атрибута?