Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
属性助手方法的c#泛型_C#_Generics_.net Core - Fatal编程技术网

属性助手方法的c#泛型

属性助手方法的c#泛型,c#,generics,.net-core,C#,Generics,.net Core,我找不到一个好方法使这个在.Net内核中干燥。(不要重复)。我怎样才能做到不重复大部分逻辑?以下是两种方法: public static string GetCategory(this Enum val) { CategoryAttribute[] attributes = (CategoryAttribute[])val .GetType() .GetField(val.ToString())

我找不到一个好方法使这个在.Net内核中干燥。(不要重复)。我怎样才能做到不重复大部分逻辑?以下是两种方法:

    public static string GetCategory(this Enum val)
    {
        CategoryAttribute[] attributes = (CategoryAttribute[])val
            .GetType()
            .GetField(val.ToString())
            .GetCustomAttributes(typeof(CategoryAttribute), false);
        return attributes.Length > 0 ? attributes[0].Category : string.Empty;
    }


    public static string GetDescription(this Enum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
            .GetType()
            .GetField(val.ToString())
            .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }

您可以使用的泛型版本,它将代码简化到不需要另一个抽象的地方

public static string GetCategory(this Enum val)
{
    return val.GetType()
          .GetField(val.ToString())
          .GetCustomAttribute<CategoryAttribute>(false)?.Category ?? string.Empty;
}

public static string GetDescription(this Enum val)
{
    return val.GetType()
          .GetField(val.ToString())
          .GetCustomAttribute<DescriptionAttribute>(false)?.Description ?? string.Empty;
}
公共静态字符串GetCategory(此枚举值)
{
return val.GetType()
.GetField(val.ToString())
.GetCustomAttribute(false)?.Category?字符串。空;
}
公共静态字符串GetDescription(此枚举值)
{
return val.GetType()
.GetField(val.ToString())
.GetCustomAttribute(false)?.Description??字符串。空;
}
我首先要说:

public static T GetAttribute<T>(this Enum val)
    where T : Attribute
{
    return (T)val
    .GetType()
    .GetField(val.ToString())
    .GetCustomAttribute(typeof(T), false);
}
publicstatict GetAttribute(此枚举值)
其中T:Attribute
{
返回(T)值
.GetType()
.GetField(val.ToString())
.GetCustomAttribute(typeof(T),false);
}
将您的方法转化为:

public static string GetCategory(this Enum val)
{
    return val.GetAttribute<CategoryAttribute>()?.Category ?? string.Empty;
}


public static string GetDescription(this Enum val)
{
    return val.GetAttribute<DescriptionAttribute>()?.Description ?? string.Empty;
}
公共静态字符串GetCategory(此枚举值)
{
返回val.GetAttribute()?.Category??string.Empty;
}
公共静态字符串GetDescription(此枚举值)
{
返回val.GetAttribute()?.Description??string.Empty;
}
可以说,您可以做更多的工作来让这些最终方法变得更加干燥,但我猜您在这里使用的模式(从属性获取属性并返回其值或空字符串)可能不够常见,不值得专门为此创建一个方法。另一方面,
GetAttribute
方法可能更易于重用。

在C#7.3中,可以将方法约束为枚举类型。 这将为您节省枚举的一个装箱

public static class AttributeExtensions
{
    public static string GetCategory<T>(this T val) where T: Enum
    {
        return GetAttr<CategoryAttribute, T>(val)?.Category ?? "";
    }

    public static string GetDescription<T>(this T val) where T : Enum
    {
        return GetAttr<DescriptionAttribute, T>(val)?.Description ?? "";
    }

    private static TAttr GetAttr<TAttr, T>(this T val) where TAttr : Attribute
    {
        return (TAttr)typeof(T)
            .GetField(val.ToString())
            ?.GetCustomAttributes(typeof(TAttr), false)
            ?.FirstOrDefault();
    }
}
公共静态类属性扩展
{
公共静态字符串GetCategory(此T val),其中T:Enum
{
返回GetAttr(val)?.Category;
}
公共静态字符串GetDescription(此T val),其中T:Enum
{
返回GetAttr(val)?.Description;
}
私有静态TAttr GetAttr(此T val),其中TAttr:Attribute
{
返回(TAttr)类型(T)
.GetField(val.ToString())
?GetCustomAttributes(typeof(TAttr),false)
?.FirstOrDefault();
}
}
此外,在使用反射时,缓存以提高性能也很重要:

public static class AttributeExtensions
{
    private class EnumMetadata
    {
        public CategoryAttribute CategoryAttribute { get; set; }
        public DescriptionAttribute DescriptionAttribute { get; set; }
    }

    private class EnumMetadataCache<T> where T : Enum
    {
        private static readonly ConcurrentDictionary<T, EnumMetadata> MetadataCache = new ConcurrentDictionary<T, EnumMetadata>();

        public static EnumMetadata GetMetadata(T item)
        {
            return MetadataCache.GetOrAdd(item, val =>
                new EnumMetadata
                {
                    CategoryAttribute = GetAttr<CategoryAttribute, T>(val),
                    DescriptionAttribute = GetAttr<DescriptionAttribute, T>(val)
                }
            );
        }
    }

    public static string GetCategory<T>(this T val) where T : Enum
    {
        return EnumMetadataCache<T>.GetMetadata(val).CategoryAttribute?.Category ?? "";
    }

    public static string GetDescription<T>(this T val) where T : Enum
    {
        return EnumMetadataCache<T>.GetMetadata(val).DescriptionAttribute?.Description ?? "";
    }

    private static TAttr GetAttr<TAttr, T>(this T val) where TAttr : Attribute
    {
        return (TAttr)typeof(T)
            .GetField(val.ToString())
            ?.GetCustomAttributes(typeof(TAttr), false)
            ?.FirstOrDefault();
    }
}
公共静态类属性扩展
{
私有类枚举元数据
{
公共类别属性类别属性{get;set;}
公共描述符属性描述符属性{get;set;}
}
私有类EnumMetadataCache,其中T:Enum
{
私有静态只读ConcurrentDictionary MetadataCache=新ConcurrentDictionary();
公共静态枚举元数据GetMetadata(T项)
{
返回MetadataCache.GetOrAdd(项,val=>
新枚举元数据
{
CategoryAttribute=GetAttr(val),
DescriptionAttribute=GetAttr(val)
}
);
}
}
公共静态字符串GetCategory(此T val),其中T:Enum
{
返回EnumMetadataCache.GetMetadata(val.CategoryAttribute?.Category??”;
}
公共静态字符串GetDescription(此T val),其中T:Enum
{
返回EnumMetadataCache.GetMetadata(val.DescriptionAttribute?.Description??”;
}
私有静态TAttr GetAttr(此T val),其中TAttr:Attribute
{
返回(TAttr)类型(T)
.GetField(val.ToString())
?GetCustomAttributes(typeof(TAttr),false)
?.FirstOrDefault();
}
}

这是.NET Framework还是.NET Standard/Core?用
TAttribute
type参数替换属性类型。将访问器Func作为参数添加到帮助器中,而不是尝试直接检索属性,例如调用helper@Haytam这是.net核心。
…这是.net核心。
这已经干了。但是,我喜欢下面发布的StriplingWarrior的答案。记住将
false
传递到该方法中,以保持OP的行为。谢谢@Igor。我打算用这个答案。如果添加另一个helper方法,则其所需的代码将更少。你的回答也是正确的。