.net dotnet核心中的枚举描述属性

xwmevbvl  于 2023-10-21  发布在  .NET
关注(0)|答案(6)|浏览(127)

我们在dot net CLI中有枚举的Description属性吗?(网络核心RC2)如果没有,任何替代方案?

brc7rcf0

brc7rcf01#

我不得不修改@yaniv的答案,以使用DescriptionAttribute类型并获取Description字段。

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;
    }
}
hpxqektj

hpxqektj3#

更新了NET 7+的答案(10/19/2023)
使用NET DescriptionAttribute
使用

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
}

添加了任一静态的示例用法:

var myDescription = myEnum.Description();
zxlwwiss

zxlwwiss4#

DescriptionAttribute was added to CoreFX,但仅在RC2之后。所以它将在RTM版本中出现,但不在RC2中。根据您想要做的事情,创建自己的属性可能会起作用。

pprl5pva

pprl5pva5#

您可以使用“DisplayAttribute”并执行

public static string Description(this Enum enumValue)
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<DisplayAttribute>()
                        .GetDescription();
    }
7rtdyuoh

7rtdyuoh6#

为了避免按照@pamcevoj的回答使用System.Reflection和按照@HouseCat的回答使用dynamic,我在@HouseCat的解决方案上构建了.NET Core 3.1中的这个解决方案

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 ?? "";
    }

相关问题