【问题标题】:Accessing attributes on fields using extension method使用扩展方法访问字段的属性
【发布时间】:2013-03-25 05:45:17
【问题描述】:

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

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

【问题讨论】:

  • 是的,这是可能的,而且微不足道。你试过什么?
  • 是的,它看起来确实微不足道,但我找不到一个例子。这就是我在这里问的原因。
  • 不要使用object,否则会涉及转换。使用额外的通用参数(即R)。此外,该成员也可以是PropertyInfo(在这种情况下就是这样)。如果您只对属性感兴趣,MemberInfo 可能就足够了。

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


【解决方案1】:

你快到了!这应该可以工作(未经测试)。

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

用法:

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

注意:从 .NET 4.5 及更高版本(包括 .NET Core)开始,BCL 提供了一个 GetCustomAttribute&lt;T&gt;(MemberInfo) extension method,其功能与上面定义的 GetAttribute 方法相同,如果可用,应改为使用。

【讨论】:

  • 如果我没记错的话,我们需要三个参数来调用这个方法。我正在寻找像这样的东西 var myClass = new MyClass(); var 属性 = myClass.GetAttribute(c => c.Height);
  • @RK:AFAIK,你是对的。你可以让它“流利”来帮助解决这个问题。将编辑答案。
  • 我认为这是在 .NET 4.5 中。但我也不确定。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 2012-12-15
    相关资源
    最近更新 更多