ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个类型 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,然后才能确定该属性是否具有属性。
This 可能也有帮助。

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

这避免了必须实现任何属性实例(即它比 GetCustomAttribute[s]().


好建议。然而,我需要属性实例,但我喜欢它。
我只是在寻找一种方法来检查属性是否存在,而不会产生调用属性 get 的副作用。谢谢马克,它工作!
@ÖrjanJämte 即使使用 GetCustomAttributes 也不会调用属性 get;但是,该属性是instantiated,它不是免费的。如果您不需要检查属性的具体值,IsDefined 更便宜。在 4.5 中,有一些方法可以检查实例化数据而无需实际创建任何属性实例(尽管这打算仅用于非常特定的场景)
对于 dotnet 核心: var props = t.GetProperties().Where(e => e.IsDefined(typeof(MyAttribute)));
w
wsanville

我最终使用最多的解决方案是基于 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 - “我通常想对属性和属性做一些事情”是我一直在寻找的 - 非常感谢您发布您的答案!
B
Black Frog

据我所知,在以更智能的方式使用反射库方面没有更好的方法。但是,您可以使用 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'

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


P
P Daddy

总是有 LINQ:

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

f
flq

如果你经常处理反射中的属性,那么定义一些扩展方法是非常非常实用的。你会在很多项目中看到这一点。这是我经常遇到的一个:

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

f
feeeper

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

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

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


@cogumel0 首先,确保 .Any() 不检查长度。但我的答案不是关于找到具有唯一一个属性的属性。其次,我不确定您是否正确阅读了代码 - 在 GetCustomAttrubutes 方法的结果上调用了 .Any 方法。所以 propertiesWithMyAttribute 的类型将是属性的集合。查看 dotnetfiddle 上的示例(我将链接添加到答案)。
您可以将 .Where 替换为 .Any,因为 .Any 也允许使用 lambda。
R
RoJaIt

我将 selfe 作为类 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}");
}

编译指示可以被删除,但我不想要任何警告......