C# return [Description] attribute based on filtering on a custom attribute

Viewed 294

I have a custom attribute with a bool value. I want to return the [Description] only for enum values where the custom value is true.

Sample:

    [Description("Concept Set Model")]
    [ModelIsDesignTimeDefinable(true)]
    ConceptSet = 1 << 24

I have these two extension methods, but they're obviously incorrect because they need to work together:

public static IEnumerable<string> ExtractDescriptionAttrib(this IEnumerable<string> set, Type type) => set
    .Select(n => type.GetMember(n).First())
    .SelectMany(member => member
        .GetCustomAttributes(typeof(DescriptionAttribute), true)
        .Cast<DescriptionAttribute>())
    .Select(x => x.Description);

public static IEnumerable<bool> ExtractDefinableAttrib(this IEnumerable<string> set, Type type) => set
    .Select(n => type.GetMember(n).First())
    .SelectMany(member => member
        .GetCustomAttributes(typeof(ModelIsDesignTimeDefinableAttribute), true)
        .Cast<ModelIsDesignTimeDefinableAttribute>())
    .Select(x => x.Definable);

My original calling code:

public static IEnumerable<string> GetModelDescriptions()
{
    var type = typeof(ModelType);
    var set = Enum.GetValues(type)
        .Cast<ModelType>()
        .Where(x => x > 0)
        .Select(x => x.ToString());

    // return with " Model" clipped off the end
    return set
        .ExtractDescriptionAttrib(type)
        .Select(x => x[0..^6]);
}

I'm sure the solution is straightforward, but I'm missing it.

1 Answers

I've come up with something that works, but it needs a better name and you might want to tweak it depending on just how you want to call it.

public static IEnumerable<string> GetDescriptions<TEnum, TCustomAttribute>(
    Func<TCustomAttribute, bool> predicate)
    where TEnum : System.Enum
    where TCustomAttribute : Attribute
{
    return typeof(TEnum)
        .GetFields(BindingFlags.Static | BindingFlags.Public)
        .Where(x =>
        {
            var descriptionAttr = x.GetCustomAttribute<DescriptionAttribute>(true);
            var customAttr = x.GetCustomAttribute<TCustomAttribute>(true);

            return x.DeclaringType == typeof(TEnum)
                && descriptionAttr != null
                && customAttr != null
                && predicate(customAttr);
        })
        .Select(x => x.GetCustomAttribute<DescriptionAttribute>().Description);
}

Defining an enum like so:

public enum Test
{
    [Description("Concept Set Model")]
    [ModelIsDesignTimeDefinable(true)]
    ConceptSet = 1,
    [Description("Concept Set Model 2")]
    [ModelIsDesignTimeDefinable(false)]
    ConceptSet2 = 2,
    [Description("Concept Set Model 3")]
    ConceptSet3 = 4,
}

and calling it with:

var descriptions = GetDescriptions<Test, ModelIsDesignTimeDefinableAttribute>(x => x.Definable == true);

foreach (var item in descriptions)
{
    Console.WriteLine(item);
}

produces:

Concept Set Model
Related