Классы дружбы С#/метаданные и отражение

Я пытаюсь использовать отражение, чтобы проверить, имеют ли свойства в данном классе атрибут ReadOnly. Классы, которые я использую, - это модели MVC View (с использованием частичного "приятеля" для метаданных.

 public partial class AccountViewModel  
{
    public virtual Int32 ID { get; set; } 
    public virtual decimal Balance { get; set; }    

} 
[MetadataType(typeof(AccountViewModelMetaData))]
public partial class AccountViewModel  
{
    class AccountViewModelMetaData
    {
        [DisplayName("ID")]
        public virtual Int32 ID { get; set; }

        [DisplayName("Balance")]
        [DataType(DataType.Currency)] 
        [ReadOnly(true)]
        public virtual decimal Balance { get; set; }

    }
}

Я хочу проверить, имеет ли свойство "Баланс" свойство ReadOnly. Если я устанавливаю атрибут ReadOnly в свойстве Balance AccountViewModel, я могу получить его следующим образом:

Type t = typeof(AccountViewModel);
PropertyInfo pi = t.GetProperty("Balance");  
bool isReadOnly =  ReadOnlyAttribute.IsDefined(pi,typeof( ReadOnlyAttribute);

Я не могу получить информацию об атрибуте, если она находится в классе метаданных. Как проверить, существует ли атрибут? У меня есть классы метаданных, определенные для всех моделей моего представления, и вам нужен общий способ проверки атрибутов в классах метаданных.

Любые предложения?

Ответ 1

решение заключается в использовании GetCustomAttributes для получения типов MetaData и проверки свойств на них.

Type t = typeof(MyClass);
PropertyInfo pi = t.GetProperty(PropertyName);  
bool isReadOnly = ReadOnlyAttribute.IsDefined(pi, typeof(ReadOnlyAttribute));

if (!isReadOnly)
{
    //check for meta data class.
    MetadataTypeAttribute[] metaAttr = (MetadataTypeAttribute[])t.GetCustomAttributes(typeof(MetadataTypeAttribute),true);

    if (metaAttr.Length > 0)
    {
        foreach (MetadataTypeAttribute attr in metaAttr)
        {
            t = attr.MetadataClassType;
            pi = t.GetProperty(PropertyName);

            if (pi != null) isReadOnly = ReadOnlyAttribute.IsDefined(pi, typeof(ReadOnlyAttribute));

            if (isReadOnly) break;
        }
    }
} 

Ответ 2

Ниже приведен короткий, но рабочий пример, обратите внимание, что я сделал вложенный класс internal, чтобы быть видимым снаружи.

public partial class AccountViewModel
{
    internal class AccountViewModelMetaData
    {
        public virtual Int32 ID { get; set; }
        [ReadOnlyAttribute(false)]
        public virtual decimal Balance { get; set; }
    }

    public virtual Int32 ID { get; set; }
    public virtual decimal Balance { get; set; }
}
class Program
{
    public static void Main(string[] args)
    {
        Type metaClass = typeof(AccountViewModel.AccountViewModelMetaData);

        bool hasReadOnlyAtt = HasReadOnlyAttribute(metaClass, "Balance");

        Console.WriteLine(hasReadOnlyAtt);
    }

    private static bool HasReadOnlyAttribute(Type type, string property)
    {
        PropertyInfo pi = type.GetProperty(property);

        return ReadOnlyAttribute.IsDefined(pi, typeof(ReadOnlyAttribute));
    }
}

Также имейте в виду, что это проверяет наличие атрибута. Вы можете в этом примере указать атрибут, но указать значение false. Если вы хотите проверить, доступно ли свойство только для чтения, вы можете не только использовать метод ReadOnlyAttribute.IsDefined.