Can an extension method be added to a class property to get the value of an attribute associated with the property?

StackOverflow https://stackoverflow.com/questions/7034753

Question

I have several classes with attributes assigned to them. The one I'm mostly interested in is the FieldLength.MaxLength value.

/// <summary>
/// Users
/// </summary>
[Table(Schema = "dbo", Name = "users"), Serializable]
public partial class Users
{

    /// <summary>
    /// Last name
    /// </summary>
    [Column(Name = "last_name", SqlDbType = SqlDbType.VarChar)]
    private string _LastName;
    [FieldLength(MaxLength=25), FieldNullable(IsNullable=false)]
    public string LastName
    {
        set { _LastName = value; }
        get { return _LastName; }
    }

}

I need to know if it's possible to write some kind of extension method for the properties in my class to return the MaxLength value of the FieldLength attribute?

For instance. I'd like to be able to write something like the following…

Users user = new Users();
int lastNameMaxLength = user.LastName.MaxLength();
Was it helpful?

Solution

No. Because the syntax you propose returns the value of the LastName property and not the property itself.

In order to retrieve and make use of the attributes, you'll need to use reflection which means you need to know the property itself.

As an idea, you could achieve this neatly by using LINQ's Expression library though to resolve the property for the object.

Example syntax you might look for:

var lastNameMaxLength = AttributeResolver.MaxLength<Users>(u => u.LastName);

Where:

public class AttributeResolver
{
    public int MaxLength<T>(Expression<Func<T, object>> propertyExpression)
    {
        // Do the good stuff to get the PropertyInfo from the Expression...
        // Then get the attribute from the PropertyInfo
        // Then read the value from the attribute
    }
}

I've found this class helpful in resolving properties from Expressions:

public class TypeHelper
{
    private static PropertyInfo GetPropertyInternal(LambdaExpression p)
    {
        MemberExpression memberExpression;

        if (p.Body is UnaryExpression)
        {
            UnaryExpression ue = (UnaryExpression)p.Body;
            memberExpression = (MemberExpression)ue.Operand;
        }
        else
        {
            memberExpression = (MemberExpression)p.Body;
        }
        return (PropertyInfo)(memberExpression).Member;
    }

    public static PropertyInfo GetProperty<TObject>(Expression<Func<TObject, object>> p)
    {
        return GetPropertyInternal(p);
    }
}

OTHER TIPS

No, this is not possible. You could add an extension method on Users though:

public static int LastNameMaxLength(this Users user) {
    // get by reflection, return
}

To save typing, you could further refine Jason's Extension to something like this.

public static void MaxLength<T>(this T obj, Expression<Func<T, object>> property)

This way it will appear on all object (unless you specify a where T restriction) and you have a compile-time safe implementation of the Property Accessor as you would use the code as:

user.MaxLength(u => u.LastName);

That's not possible in that form. The best you can manage is a method that takes a lambda expression, gets the property associated with it and then use reflection to obtain the attribute.

int GetMaxLength<T>(Expression<Func<T,string>> property);

And call it like:

GetMaxLength<Users>((u)=>LastName)

You could write an extension method, but it would have to accept a first parameter of PropertyInfo rather than string (since the string itself has no attributes.) It would look something like this:

public static int GetMaxLength(this PropertyInfo prop)
{
    // TODO: null check on prop
    var attributes = prop.GetCustomeAttributes(typeof(FieldLengthAttribute), false);
    if (attributes != null && attributes.Length > 0)
    {
        MaxLengthAttribute mla = (MaxLengthAttribute)attributes[0];
        return mla.MaxLength;
    }

    // Either throw or return an indicator that something is wrong
}

You then get the property via reflection:

int maxLength = typeof(Users).GetProperty("LastName").GetMaxLength();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top