我找不到在.Net Core中制作DRY的好方法。(不要重复自己(。我怎样才能做到不重复大部分逻辑?以下是 2 种方法:
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 T GetAttribute<T>(this Enum val)
where T : Attribute
{
return (T)val
.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;
}
你可以做更多的事情来使这些最终方法更加 DRY,但我猜你在这里使用的模式(从属性中获取属性并返回其值或空字符串(可能不够常见,值得为此创建一个方法。另一方面,GetAttribute
方法可能更容易重用。
您可以使用GetCustomAttribute<T>
的通用版本,这足以简化代码,使其不需要其他抽象 IMO。
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;
}
在 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();
}
}
此外,在使用反射时,缓存以提高性能也很重要:
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();
}
}