Search code examples
c#linqextension-methodscustom-attributes

Accessing attributes on fields using extension method


I want to check custom attributes on my class members (fields only) by using an extension method.

public class DatabaseIdAttribute : Attribute
{
    public int ID { get; set; }

    public DatabaseIdAttribute(int id)
    {
        this.ID = id;
    }
}

public class MyClass 
{
    [DatabaseId(1)]
    double Height {get;set;}

    [DatabaseId(2)]
    double Width {get;set;}

    double Area { get { return this.Height * this.Width; }
}

I want to use LINQ expression in the extension method to access the class field instead of passing magic strings.

var myClass = new MyClass();
var attribute = myClass.GetAttribute<DatabaseIdAttribute>(c => c.Height);

Is it possible to achieve?

[EDIT]

For the time being, I have achieved the following with the help of @leppie

    public static MemberInfo GetMember<T, R>(this T instance, Expression<Func<T, R>> selector)
    {
        var member = selector.Body as MemberExpression;
        if (member != null)
        {
            return member.Member;
        }
        return null;
    }

    public static T GetAttribute<T>(this MemberInfo member) where T : Attribute
    {
        return member.GetCustomAttributes(false).OfType<T>().SingleOrDefault();
    }

which enables to get the attribute in the following way

var c = new MyClass();
var attribute = c.GetMember(m => m.Height).GetAttribute<DatabaseIdAttribute>();

but I want to be able to access it in the following way

var c = new MyClass();
var attribute = c.GetAttribute<DatabaseIdAttribute>(m => m.Height);

Solution

  • You are almost there! This should work (untested).

    public static class ObjectExtensions
    {
        public static MemberInfo GetMember<T,R>(this T instance, 
             Expression<Func<T, R>> selector)
        {
            var member = selector.Body as MemberExpression;
            if (member != null)
            {
                return member.Member;
            }
            return null;
        }
    
        // unnecessary in .NET 4.5 and up, see note!
        public static T GetAttribute<T>(this MemberInfo meminfo) where T : Attribute
        {
           return meminfo.GetCustomAttributes(typeof(T)).FirstOrDefault() as T;
        }
    }
    

    Usage:

    var attr = someobject.GetMember(x => x.Height).
                  GetAttribute<DatabaseIdAttribute>();
    

    Note: As of .NET 4.5 and up (including .NET Core), the BCL provides a GetCustomAttribute<T>(MemberInfo) extension method that functions identically to the GetAttribute method defined above, and should be used instead if available.