views:

424

answers:

2

I am trying to use reflection to check if properties on a given class have a ReadOnly attribute set. The classes I am using are MVC View Models (using a partial "buddy" class for the metadata.

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

    }
}

I want to check if "Balance" has the ReadOnly property. If i set the ReadOnly attribute on the Balance property of AccountViewModel, i can retrieve it this way:

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

I can't retrieve the attribute info if it is on the meta data class. How can i check if the attribute exists? I have meta data classes defined for all my view models, and need a generic way to check for attributes on meta data classes.

Any suggestions?

+1  A: 

A short but working example follows, note that I made the nested class internal in order to be visible to the outside.

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

Also be aware that this checks for the existence of the attribute. You can has in this example specify the attribute but provide the value of false. If you want to check if the property is read-only or not, you can't only use the method ReadOnlyAttribute.IsDefined.

João Angelo
+2  A: 

the solution is to use GetCustomAttributes to get MetaData types and check the properties on those as well...

  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;
                }
            }
        } 
Brian
Beware that you're checking that the attribute exists and not that it is defined has `true`. Have you considered what happens if the property is defined has `[ReadOnlyAttribute(false)]`?
João Angelo