Enum Description attribute in dotnet core
Asked Answered
C

6

20

Do we have Description attribute for Enums in dot net CLI? (Dot Net Core RC2) If not, any alternative?

Chabazite answered 18/5, 2016 at 17:4 Comment(0)
S
16

For 1.0 and 1.1, DescriptionAttribute is now in the System.ComponentModel.Primitives NuGet package.

Shockey answered 18/4, 2017 at 23:51 Comment(0)
A
20

I had to modify @yaniv's answer to use the DescriptionAttribute type and get the Description field.

public static class EnumExtensions
{
    /// <summary>
    /// Get the Description from the DescriptionAttribute.
    /// </summary>
    /// <param name="enumValue"></param>
    /// <returns></returns>
    public static string GetDescription(this Enum enumValue)
    {
        return enumValue.GetType()
                   .GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DescriptionAttribute>()?
                   .Description ?? string.Empty;
    }
}
Almira answered 25/3, 2019 at 13:9 Comment(0)
S
16

For 1.0 and 1.1, DescriptionAttribute is now in the System.ComponentModel.Primitives NuGet package.

Shockey answered 18/4, 2017 at 23:51 Comment(0)
L
14

Updated Answer for NET7+ (10/19/2023)
Using the NET DescriptionAttribute with internal Caching to aid in performance.

Using

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;

Class

public static class EnumExtensions
{
    private static readonly Dictionary<Type, Dictionary<object, string>> _enumTypeMemberDescriptionCache = new Dictionary<Type, Dictionary<object, string>>();

    public static void PreCacheEnumDescriptions(params Type[] scanMarkers)
    {
        foreach (var scanMarker in scanMarkers)
        {
            var enumTypes = scanMarker
                .Assembly
                .ExportedTypes
                .Where(x => x.IsEnum);

            CacheEnumExportTypes(enumTypes);
        }
    }

    private static void CacheEnumExportTypes(IEnumerable<Type> enumTypes)
    {
        foreach (var type in enumTypes)
        {
            if (!type.IsEnum) continue;

            CacheEnumMemberDescriptionValues(type);
        }
    }

    private static void CacheEnumMemberDescriptionValues(Type enumType)
    {
        var enums = Enum.GetValues(enumType);

        foreach (Enum enumMember in enums)
        {
            var enumTypeCached = _enumTypeMemberDescriptionCache.ContainsKey(enumType);
            var enumFieldCached = enumTypeCached && _enumTypeMemberDescriptionCache[enumType].ContainsKey(enumMember);

            if (enumTypeCached && enumFieldCached)
            {
                continue;
            }

            if (!enumTypeCached)
            {
                _enumTypeMemberDescriptionCache[enumType] = new Dictionary<object, string>();
            }

            if (!enumFieldCached)
            {
                _ = FindAndCacheEnumDescription(enumType, enumMember);
            }
        }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static string GetDescription<TEnum>(this TEnum enumMember) where TEnum : notnull
    {
        if (enumMember == null) return null;

        var enumType = typeof(TEnum);
        var enumTypeCached = _enumTypeMemberDescriptionCache.ContainsKey(enumType);
        var enumFieldCached = enumTypeCached && _enumTypeMemberDescriptionCache[enumType].ContainsKey(enumMember);

        if (enumTypeCached && enumFieldCached)
        {
            return _enumTypeMemberDescriptionCache[enumType][enumMember];
        }

        if (!enumTypeCached)
        {
            _enumTypeMemberDescriptionCache[enumType] = new Dictionary<object, string>();
        }

        return FindAndCacheEnumDescription(enumType, enumMember);
    }

    [MethodImpl(MethodImplOptions.AggressiveOptimization)]
    private static string FindAndCacheEnumDescription<TEnum>(Type enumType, TEnum enumMember) where TEnum : notnull
    {
        var attributes = enumType
            .GetField(enumMember.ToString())
            ?.GetCustomAttributes(false);

        if (attributes != null)
        {
            foreach (var attribute in attributes.OfType<DescriptionAttribute>())
            {
                _enumTypeMemberDescriptionCache[enumType][enumMember] = attribute.Description;
                return attribute.Description;
            }
        }

        return enumMember.ToString();
    }
}

The update adds basic level caching, removes Dynamic, allows also for OnStart PreCache. Very simple usages as follows

// Give it a Type inside the Assembly to scan for Enums and cache description.
EnumExtensions.PreCacheEnumDescriptions(typeof(StaticClassWithEnums));

// If not pre-cached, first will use light reflection to find Description attribute.
var description = EnumType.EnumMember.GetDescription();
// Second call uses in-memory cached value.
description = EnumType.EnumMember.GetDescription();

Bonus Razor Page/MVC HTML Static Helper for Html
An implementation of GetEnumSelectListWithDescriptions()

private static readonly Dictionary<Type, IEnumerable<SelectListItem>> _enumSelectListCache = new Dictionary<Type, IEnumerable<SelectListItem>>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IEnumerable<SelectListItem> GetEnumSelectListWithDescriptions<TEnum>(this IHtmlHelper _)
    where TEnum : Enum
{
    var enumType = typeof(TEnum);

    if (_enumSelectListCache.ContainsKey(enumType))
    {
        return _enumSelectListCache[enumType];
    }

    var enumSelectList = Enum
        .GetValues(typeof(TEnum))
        .OfType<TEnum>()
        .Select(
            e => new SelectListItem
            {
                Value = e.ToString(),
                Text = e.GetDescription()
            });

    _enumSelectListCache[enumType] = enumSelectList;
    return enumSelectList;
}

ORIGINAL ANSWERS

I used this for my Net Framework implementation:

public static class EnumerationExtension
{
    public static string Description( this Enum value )
    {
        // get attributes  
        var field = value.GetType().GetField( value.ToString() );
        var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );

        // return description
        return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
    }
}

This doesn't work for NetCore so I modified it to do this:

public static class EnumerationExtension
{
    public static string Description( this Enum value )
    {
        // get attributes  
        var field = value.GetType().GetField( value.ToString() );
        var attributes = field.GetCustomAttributes( false );

        // Description is in a hidden Attribute class called DisplayAttribute
        // Not to be confused with DisplayNameAttribute
        dynamic displayAttribute = null;
         
        if (attributes.Any())
        {
            displayAttribute = attributes.ElementAt( 0 );
        }

        // return description
        return displayAttribute?.Description ?? "Description Not Found";
    }
}

Enumeration Example:

public enum ExportTypes
{
    [Display( Name = "csv", Description = "text/csv" )]
    CSV = 0
}

Sample Usage for either static added:

var myDescription = myEnum.Description();
Lawgiver answered 5/1, 2017 at 16:27 Comment(0)
V
3

DescriptionAttribute was added to CoreFX, but only after RC2. So it will be there in the RTM version, but not in RC2. Depending on what you want to do, creating your own attribute might work.

Veta answered 22/5, 2016 at 14:24 Comment(0)
N
3

You can use "DisplayAttribute" and do

    public static string Description(this Enum enumValue)
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<DisplayAttribute>()
                        .GetDescription();
    }
Necessitarianism answered 2/10, 2018 at 9:51 Comment(0)
H
1

To avoid using System.Reflection as per @pamcevoj's answer and dynamic as per @HouseCat's answer I came to this solution in .NET Core 3.1 building on @HouseCat's solution

public static string Description(this Enum enumValue)
    {
        var descriptionAttribute = enumValue.GetType()
            .GetField(enumValue.ToString())
            .GetCustomAttributes(false)
            .SingleOrDefault(attr => attr.GetType() == typeof(DescriptionAttribute)) as DescriptionAttribute;

        // return description
        return descriptionAttribute?.Description ?? "";
    }
Herrington answered 20/1, 2021 at 10:43 Comment(2)
This is still using reflection, yes?Suppletory
@AdamTegen Correct.. FieldInfo and MemberInfo are both in System.Reflection.. My bad!Herrington

© 2022 - 2024 — McMap. All rights reserved.