如何获得具有给定属性的属性列表?


210

我有一个类型,t我想获取具有属性的公共属性的列表MyAttribute。该属性用标记AllowMultiple = false,如下所示:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]

目前我所拥有的是这个,但是我在想有一种更好的方法:

foreach (PropertyInfo prop in t.GetProperties())
{
    object[] attributes = prop.GetCustomAttributes(typeof(MyAttribute), true);
    if (attributes.Length == 1)
    {
         //Property with my custom attribute
    }
}

我该如何改善?我很抱歉,如果这是重复的,那儿有大量的反射线程……似乎这是一个非常热门的话题。


不。在确定该属性是否具有属性之前,需要一个PropertyInfo。
汉斯·帕桑

Answers:


391
var props = t.GetProperties().Where(
                prop => Attribute.IsDefined(prop, typeof(MyAttribute)));

这避免了必须实例化任何属性实例(即,它比便宜GetCustomAttribute[s]()


1
好建议。但是,我将需要属性实例,但是我喜欢它。
wsanville 2010年

1
我只是在寻找一种方法来检查属性的存在,而不会产生调用属性get的副作用。谢谢马克,工作正常!
与OrjanJämte

1
@ÖrjanJämte get即使使用GetCustomAttributes,也不会调用该属性;但是,该属性是实例化的,它不是免费的。如果您不需要检查属性的特定值,IsDefined则价格便宜。在4.5中,有一些方法可以在实际创建任何属性实例的情况下检查实例化数据(尽管这仅适用于非常特定的场景)
Marc Gravell


2
对于dotnet核心:var props = t.GetProperties()。Where(e => e.IsDefined(typeof(MyAttribute)));
Rtype

45

我最终使用最多的解决方案基于Tomas Petricek的回答。我通常想同时使用属性和属性。

var props = from p in this.GetType().GetProperties()
            let attr = p.GetCustomAttributes(typeof(MyAttribute), true)
            where attr.Length == 1
            select new { Property = p, Attribute = attr.First() as MyAttribute};

+1-我一直在寻找“我通常想同时使用属性和属性”-非常感谢您发布答案!
Yawar Murtaza

34

据我所知,在以更聪明的方式使用反射库方面没有更好的方法。但是,您可以使用LINQ使代码更好:

var props = from p in t.GetProperties()
            let attrs = p.GetCustomAttributes(typeof(MyAttribute), true)
            where attrs.Length != 0 select p;

// Do something with the properties in 'props'

我相信这可以帮助您以更具可读性的方式来构造代码。


13

总有LINQ:

t.GetProperties().Where(
    p=>p.GetCustomAttributes(typeof(MyAttribute), true).Length != 0)

6

如果您定期处理反射中的属性,则定义一些扩展方法非常非常实用。您将在许多项目中看到这一点。这是我经常遇到的一个:

public static bool HasAttribute<T>(this ICustomAttributeProvider provider) where T : Attribute
{
  var atts = provider.GetCustomAttributes(typeof(T), true);
  return atts.Length > 0;
}

你可以像这样使用 typeof(Foo).HasAttribute<BarAttribute>();

其他项目(例如StructureMap)具有成熟的ReflectionHelper类,这些类使用Expression树具有良好的语法来标识(例如PropertyInfos)。用法如下所示:

ReflectionHelper.GetProperty<Foo>(x => x.MyProperty).HasAttribute<BarAttribute>()

2

除了以前的答案:最好使用method Any()而不是检查集合的长度:

propertiesWithMyAttribute = type.GetProperties()
  .Where(x => x.GetCustomAttributes(typeof(MyAttribute), true).Any());

dotnetfiddle上的示例:https ://dotnetfiddle.net/96mKep


@ cogumel0首先,请确保.Any()不检查长度。但是我的答案不是关于仅具有一个属性的已找到属性。其次,我不确定您是否正确阅读了代码-在.Any方法结果上调用的GetCustomAttrubutes方法。因此,的类型propertiesWithMyAttribute将是属性的集合。在dotnetfiddle上查看示例(我将链接添加到答案中)。
Feeeper

1
您可以将.Where替换为.Any,因为.Any还允许使用lambda。
PRMan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.