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

我有一个类型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
}
}

我该如何改进呢?如果这是一个副本,我很抱歉,有大量的反射线程在那里…看起来这是个很热门的话题。

125034 次浏览

据我所知,没有比使用Reflection库更聪明的方法了。然而,你可以使用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'

我相信这可以帮助您以更易读的方式构建代码。

总是有LINQ:

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

如果您经常在Reflection中处理attribute,那么定义一些扩展方法是非常非常实用的。您将在许多项目中看到这一点。这个是我经常用的:

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类,这些类使用表达式树具有良好的语法来标识例如PropertyInfos。使用量是这样的:

ReflectionHelper.GetProperty<Foo>(x => x.MyProperty).HasAttribute<BarAttribute>()
var props = t.GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(MyAttribute)));

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

我最终使用最多的解决方案是基于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};

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

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

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

我为类Type创建了一个扩展方法。

我使用了LINQ和c# 7.0中引入的元组。

    public static class TypeExtensionMethods
{
public static List<(PropertyInfo Info, T Attribute)> GetPropertyWithAttribute<T>(this Type type) where T : Attribute
{
#pragma warning disable CS8619 // Checked here: .Where(x => x.Value != default)


return type.GetProperties()
.Select(x => (Info: x, Attribute: GetAttribute<T>(x)))
.Where(x => x.Attribute != default)
.ToList();


#pragma warning restore CS8619 // Checked here: .Where(x => x.Value != default)
}


private static T? GetAttribute<T>(PropertyInfo info) where T : Attribute
{
return (T?)info.GetCustomAttributes(typeof(T), true)
.FirstOrDefault();
}
}

它可以这样使用:

var props = typeof(DemoClass).GetPropertyWithAttribute<MyAttribute>();


foreach((PropertyInfo Info, MyAttribute Attribute) in props)
{
Console.WriteLine($"Property {Info.Name}: {Attribute.DisplayName}");
}

pragma可以删除,但我不想要任何警告……