< Summary

Information
Class: Allyaria.Abstractions.Extensions.EnumExtensions
Assembly: Allyaria.Abstractions
File(s): /home/runner/work/allyaria/allyaria/src/Allyaria.Abstractions/Extensions/EnumExtensions.cs
Line coverage
100%
Covered lines: 34
Uncovered lines: 0
Coverable lines: 34
Total lines: 99
Line coverage: 100%
Branch coverage
100%
Covered branches: 8
Total branches: 8
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
GetDescription(...)100%22100%
GetDescription(...)100%11100%
GetSingleDescription(...)100%66100%

File(s)

/home/runner/work/allyaria/allyaria/src/Allyaria.Abstractions/Extensions/EnumExtensions.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using System.ComponentModel;
 3
 4namespace Allyaria.Abstractions.Extensions;
 5
 6/// <summary>
 7/// Provides extension methods for working with <see cref="Enum" /> values, including retrieving user-friendly descripti
 8/// from <see cref="DescriptionAttribute" /> with sensible fallbacks and caching for performance.
 9/// </summary>
 10/// <remarks>
 11/// Descriptions are cached per (enum <see cref="Type" />, raw enum <c>name</c>) to avoid repeated reflection. For
 12/// <c>[Flags]</c> combinations (e.g., <c>"Read, Write"</c>), each constituent name is resolved independently and then
 13/// re-joined using <c>", "</c>.
 14/// </remarks>
 15public static class EnumExtensions
 16{
 17    /// <summary>
 18    /// Cache of resolved descriptions keyed by a tuple of the enum <see cref="Type" /> and the raw member <c>name</c>. 
 19    /// avoids repeated reflection and attribute lookups across calls.
 20    /// </summary>
 321    private static readonly ConcurrentDictionary<(Type type, string name), string> DescriptionCache = new();
 22
 23    /// <summary>Retrieves a user-friendly description for an <see cref="Enum" /> value.</summary>
 24    /// <param name="value">The enumeration value whose description to retrieve.</param>
 25    /// <returns>
 26    /// The <see cref="DescriptionAttribute.Description" /> value when present. Otherwise, a humanized fallback derived 
 27    /// the enum member name(s). For <c>[Flags]</c> combinations, each constituent name is individually humanized and th
 28    /// results are joined with <c>", "</c>.
 29    /// </returns>
 30    /// <remarks>
 31    /// Fallback humanization is performed via <see cref="StringExtensions.FromPascalCase(string?)" />. The result is ca
 32    /// per (enum type, raw name) pair.
 33    /// </remarks>
 34    /// <exception cref="AryArgumentException">Thrown if <paramref name="value" /> is <see langword="null" />.</exceptio
 35    public static string GetDescription(this Enum value)
 36    {
 147637        AryGuard.NotNull(value: value);
 38
 147439        var type = value.GetType();
 147440        var name = value.ToString();
 41
 147442        return DescriptionCache.GetOrAdd(
 147443            key: (type, name),
 147444            valueFactory: static key =>
 147445            {
 23946                (var t, var n) = key;
 147447
 23948                if (!n.Contains(value: ','))
 147449                {
 23750                    return GetSingleDescription(enumType: t, memberName: n);
 147451                }
 147452
 253                var parts = n.Split(separator: ',')
 454                    .Select(selector: s => s.Trim())
 455                    .Where(predicate: s => s.Length > 0)
 656                    .Select(selector: part => GetSingleDescription(enumType: t, memberName: part));
 147457
 258                return string.Join(separator: ", ", values: parts);
 147459            }
 147460        );
 61    }
 62
 63    /// <summary>Strongly-typed convenience overload that defers to <see cref="GetDescription(Enum)" />.</summary>
 64    /// <typeparam name="TEnum">The enum type.</typeparam>
 65    /// <param name="value">The enumeration value whose description to retrieve.</param>
 66    /// <returns>The description string as defined by <see cref="GetDescription(Enum)" />.</returns>
 67    public static string GetDescription<TEnum>(this TEnum value)
 68        where TEnum : struct, Enum
 145469        => ((Enum)value).GetDescription();
 70
 71    /// <summary>Resolves the description for a single enum member name on a given enum <see cref="Type" />.</summary>
 72    /// <param name="enumType">The enum <see cref="Type" /> that defines the member.</param>
 73    /// <param name="memberName">The exact member name to resolve (not a composite <c>[Flags]</c> string).</param>
 74    /// <returns>
 75    /// The <see cref="DescriptionAttribute.Description" /> value if present and non-whitespace; otherwise the
 76    /// <paramref name="memberName" /> humanized via <see cref="StringExtensions.FromPascalCase(string?)" />.
 77    /// </returns>
 78    private static string GetSingleDescription(Type enumType, string memberName)
 79    {
 24180        var memberInfos = enumType.GetMember(name: memberName);
 81
 24182        if (memberInfos.Length <= 0)
 83        {
 284            return memberName.FromPascalCase();
 85        }
 86
 23987        var attr = memberInfos[0]
 23988            .GetCustomAttributes(attributeType: typeof(DescriptionAttribute), inherit: false)
 23989            .OfType<DescriptionAttribute>()
 23990            .FirstOrDefault();
 91
 23992        if (attr is not null && !string.IsNullOrWhiteSpace(value: attr.Description))
 93        {
 21794            return attr.Description;
 95        }
 96
 2297        return memberName.FromPascalCase();
 98    }
 99}