基于属性对枚举执行 LINQ 操作

Perform LINQ operations on an Enum based on Attributes

我正在尝试根据每个枚举选项的属性查询我的枚举。

我知道如何获取列表。通过这段代码非常简单:

            var list = Enum.GetValues(typeof(FamilyNameOptions))
                    .Cast<FamilyNameOptions>()
                    .Select(v => v.ToString())
                    .ToList();

如果这是我的 Enum 设置,我如何查询值为 TRUE

的属性 DrawingListIsEnabled
    public enum FamilyNameOptions
    {
        [DrawingListIsEnabled(true)]
        [FamilyUserName("FamilyName1")]
        FamilyName1= 0,

        [DrawingListIsEnabled(false)]
        [FamilyUserName("FamilyName2")]
        FamilyName2= 1,
    }


    /// <summary>
    /// DrawingListIsEnabledAttribute
    /// </summary>
    /// <seealso cref="System.Attribute" />
    [AttributeUsage(AttributeTargets.All)]
    public class DrawingListIsEnabledAttribute : Attribute
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DrawingListIsEnabledAttribute"/> class.
        /// </summary>
        /// <param name="isEnabled">if set to <c>true</c> [is enabled].</param>
        public DrawingListIsEnabledAttribute(bool isEnabled)
        {
            this.IsEnabled = isEnabled;
        }

        /// <summary>
        /// Gets a value indicating whether this instance is enabled.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsEnabled { get; private set; }
    }

预期结果将是列表 1:

FamilyName1

而不是使用 Enum.GetValues 您将需要使用反射来查找静态字段列表;

typeof(FamilyNameOptions)
    .GetFields(BindingFlags.Static | BindingFlags.Public)
    // For definition order, rather than value order;
    .OrderBy(f => f.MetadataToken)
    .Select(f => new {
        Value = (FamilyNameOptions)f.GetValue(null),
        Text = f.Name,
        Enabled = f.GetCustomAttribute<DrawingListIsEnabledAttribute>()?.IsEnabled ?? false,
        FamilyName = f.GetCustomAttribute<FamilyUserNameAttribute>()?.Name
    })

由于 none 该信息会在运行时发生变化,您可能希望创建一个辅助类型来缓存结果。

这是完成此任务的简单 LINQ 查询:

var items = Enum.GetValues<FamilyNameOptions>()
                .Select(item => item.GetType().GetMember(item.ToString()).FirstOrDefault())
                .Where(memberInfo => memberInfo?.GetCustomAttribute<DrawingListIsEnabledAttribute>().IsEnabled ?? false)
                .Select(enabledMemberInfo => enabledMemberInfo.GetCustomAttribute<FamilyUserNameAttribute>().FamilyUserName);

请注意,您不需要原件 list。另外,我使用的是 Enum.GetValues<TEnum> 的通用版本,这样您的版本就不需要 Cast

为了成为 self-documenting,我一直保留我的 LINQ 名称;随意使用典型的较短名称。代码工作如下:

  • Enum.GetValues<FamilyNameOptions> returns enum FamilyNameOptions.
  • 的 strongly-typed 成员列表
  • 第一个 .Select 语句获取描述枚举成员的 MemberInfo 个对象(以及所有自定义属性)
  • 接下来,.Where 根据 DrawingListIsEnabledAttributeIsEnabled 属性
  • 过滤结果
  • 最后,最后一个 .SelectFamilyUserNameAttributeFamilyUserName 属性 中获取名称(我想这就是它的名字 - 如果不是,请相应地更改它) .