Do we have Description
attribute for Enums in dot net CLI? (Dot Net Core RC2)
If not, any alternative?
For 1.0 and 1.1, DescriptionAttribute
is now in the System.ComponentModel.Primitives
NuGet package.
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;
}
}
For 1.0 and 1.1, DescriptionAttribute
is now in the System.ComponentModel.Primitives
NuGet package.
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();
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.
You can use "DisplayAttribute" and do
public static string Description(this Enum enumValue)
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.GetDescription();
}
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 ?? "";
}
© 2022 - 2024 — McMap. All rights reserved.