Home > Enterprise >  Perform LINQ operations on an Enum based on Attributes
Perform LINQ operations on an Enum based on Attributes

Time:02-24

I'm trying to query against my Enum based on an attribute on each enum option.

I know how to get the list. That is pretty simple via this code:

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

If this is my Enum setup, how can I query against the attribute DrawingListIsEnabled where the value is TRUE

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

The expected result would be a list of 1:

FamilyName1

CodePudding user response:

Rather than using Enum.GetValues you will need to use reflection to find the static field list;

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

Since none of that information will change at runtime, you might wish to create a helper type to cache the results.

CodePudding user response:

Here's a simple LINQ query to accomplish this task:

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

Note, you don't need your original list. Also, I'm using the generic version of Enum.GetValues<TEnum>, which eliminates the need for Cast in your version.

I kept my LINQ names long in effort to be self-documenting; feel free to go with the typical shorter names. The code works as follows:

  • Enum.GetValues<FamilyNameOptions> returns a strongly-typed list of members of enum FamilyNameOptions.
  • first .Select statement gets the MemberInfo objects describing the enum members (along with all custom attributes)
  • next, .Where filters the results based on DrawingListIsEnabledAttribute's IsEnabled property
  • finally, the last .Select grabs the names from the FamilyUserNameAttribute's FamilyUserName property (I presume that's what it's called - change it accordingly if not).
  • Related