Я новичок в отражении в C #. Я хочу создать определенный атрибут, который я могу использовать с моими полями, чтобы я мог просмотреть их все и проверить, правильно ли они инициализированы, вместо того, чтобы писать эти проверки каждый раз для каждого поля. Думаю, это будет выглядеть примерно так:

public abstract class BaseClass {

    public void Awake() {

        foreach(var s in GetAllFieldsWithAttribute("ShouldBeInitialized")) {

            if (!s) {

                Debug.LogWarning("Variable " + s.FieldName + " should be initialized!");
                enabled = false;

            }

        }

    }

}

public class ChildClass : BasicClass {

    [ShouldBeInitialized]
    public SomeClass someObject;

    [ShouldBeInitialized]
    public int? someInteger;

}

(Вы можете заметить, что я собираюсь использовать именно Unity3d, но в этом вопросе нет ничего специфического для Unity - по крайней мере, мне так кажется). Это возможно?

1
Max Yankov 25 Мар 2013 в 21:26
Существует ли System.Attribute.IsDefined (FieldInfo, Type) в единстве?
 – 
Marc Gravell
25 Мар 2013 в 21:28
Да. Спасибо - я думаю, что смогу найти выход из этого в Google, но все еще не совсем уверен, как с этим работать ...
 – 
Max Yankov
25 Мар 2013 в 21:32

1 ответ

Лучший ответ

Вы можете получить это с помощью простого выражения:

private IEnumerable<FieldInfo> GetAllFieldsWithAttribute(Type attributeType)
{
    return this.GetType().GetFields().Where(
        f => f.GetCustomAttributes(attributeType, false).Any());
}

Затем измените свой вызов на:

foreach(var s in GetAllFieldsWithAttribute(typeof(ShouldBeInitializedAttribute)))

Вы можете сделать его более полезным для всего приложения, сделав его методом расширения на Type:

public static IEnumerable<FieldInfo> GetAllFieldsWithAttribute(this Type objectType, Type attributeType)
{
    return objectType.GetFields().Where(
        f => f.GetCustomAttributes(attributeType, false).Any());
}

Вы бы назвали это так:

this.GetType().GetAllFieldsWithAttribute(typeof(ShouldBeInitializedAttribute))

Изменить : чтобы получить закрытые поля, измените GetFields() на:

GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)

И чтобы получить тип (внутри вашего цикла):

object o = s.GetValue(this);
2
Steve Czetty 25 Мар 2013 в 22:25
Как я могу получить значения этих полей? Также, как ни странно, кажется, что базовый класс видит дочерние поля только в том случае, если они объявлены общедоступными - я пробовал защищенные и внутренние, но тогда он просто игнорирует их.
 – 
Max Yankov
25 Мар 2013 в 21:57