using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
类
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();
}
}
更新增加了基本级别的缓存,删除了动态,还允许OnStart PreCache。非常简单的用法如下
// 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 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;
}
原始应答 我在我的Net Framework实现中使用了这个:
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";
}
}
这对NetCore不起作用,所以我修改了它来做到这一点:
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";
}
}
枚举示例:
public enum ExportTypes
{
[Display( Name = "csv", Description = "text/csv" )]
CSV = 0
}
6条答案
按热度按时间brc7rcf01#
我不得不修改@yaniv的答案,以使用
DescriptionAttribute
类型并获取Description
字段。gab6jxml2#
对于1.0和1.1,
DescriptionAttribute
现在在System.ComponentModel.Primitives
NuGet包中。hpxqektj3#
更新了NET 7+的答案(10/19/2023)
使用NET
DescriptionAttribute
使用
类
更新增加了基本级别的缓存,删除了动态,还允许OnStart PreCache。非常简单的用法如下
Bonus Razor Page/MVC HTML Static Helper
GetEnumSelectListWithDescriptions()
的实现原始应答
我在我的Net Framework实现中使用了这个:
这对NetCore不起作用,所以我修改了它来做到这一点:
枚举示例:
添加了任一静态的示例用法:
zxlwwiss4#
DescriptionAttribute
was added to CoreFX,但仅在RC2之后。所以它将在RTM版本中出现,但不在RC2中。根据您想要做的事情,创建自己的属性可能会起作用。pprl5pva5#
您可以使用“DisplayAttribute”并执行
7rtdyuoh6#
为了避免按照@pamcevoj的回答使用System.Reflection和按照@HouseCat的回答使用dynamic,我在@HouseCat的解决方案上构建了.NET Core 3.1中的这个解决方案