使用扩展方法访问字段上的属性

时间:2013-03-25 05:45:17

标签: c# linq extension-methods custom-attributes

我想使用扩展方法检查我的类成员(仅限字段)的自定义属性。

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

我想在扩展方法中使用LINQ表达式来访问类字段而不是传递魔术字符串。

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

有可能实现吗?

[编辑]

目前,我已经在@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();
    }

可以按以下方式获取属性

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

但我希望能够以下列方式访问它

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

2 个答案:

答案 0 :(得分:6)

你快到了!这应该有效(未经测试)。

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

    public static T GetAttribute<T>(this MemberInfo meminfo) where T : Attribute
    {
       return meminfo.GetCustomAttributes(typeof(T)).FirstOrDefault() as T;
    }
}

用法:

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

IIRC:GetAttribute<T>(this MemberInfo meminfo)已经被定义为.NET 4中的扩展方法。

答案 1 :(得分:1)

如果您不介意提供额外的通用类型,您可以这样做:

public static class ReflectionHelper
{
    public static TAttr GetAttribute<TClass, TProp, TAttr>(Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
    {
        var member = selector.Body as MemberExpression;
        return member.Member.GetCustomAttributes<TAttr>(false).First();
    }
}

然后你可以像这样使用它:

var attribute = ReflectionHelper.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);

请注意,这不是扩展方法(因为我们无法使用静态扩展),因此无需创建类的实例。

当然你仍然可以使用扩展方法版本:

public static TAttr GetAttribute<TClass, TProp, TAttr>(this TClass instance, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
   var member = selector.Body as MemberExpression;
   return member.Member.GetCustomAttributes<TAttr>(false).First();
}

您可以这样称呼它:

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

但无论哪种方式都非常冗长。如果您希望编译推断所有泛型类型,我们需要传入属性的实例:

public static class ReflectionHelper
{
    public static TAttr GetAttribute<TClass, TProp, TAttr>(TAttr attribute, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
    {
        var member = selector.Body as MemberExpression;
        return member.Member.GetCustomAttributes<TAttr>(false).First();
    }
}

用法:

var attribute = ReflectionHelper.GetAttribute(new DatabaseIdAttribute(), m => m.Height);