遍历枚举元素(不只是名称,而不仅仅是值)
Iterate over Enum elements (Not just names and not just values)
我有枚举元素和描述属性的枚举
public enum CourseGrades
{
[Description("A")]
A = 11,
[Description("A-")]
AMinus = 10,
[Description("B+")]
BPlus = 9,
[Description("B")]
B = 8,
[Description("B-")]
BMinus = 7,
[Description("C+")]
CPlus = 6,
[Description("C")]
C = 5,
[Description("C-")]
CMinus = 4,
[Description("D+")]
DPlus = 3,
[Description("D")]
D = 2,
[Description("D-")]
DMinus = 1,
[Description("E")]
E = 0,
[Description("Audit")]
AU = -1,
[Description("Incomplete")]
IC = -2,
[Description("Withdrawl")]
WD = -3,
[Description("Not Applicable")]
NA = -4
}
我的问题是我正在尝试建立一个描述列表,但我对如何做到这一点感到困惑。我看到的所有答案都说使用 Enum.GetNames()
或 Enum.GetValues()
我知道该怎么做。
这两个的问题是它们 return 一个字符串数组,它丢失了关于它来自哪里的所有上下文,所以我无法按照它来获取特定枚举值的描述我想要的。
我现在获取描述的方法是调用 CourseGrades.A.GetDescription()
,因为我有一个扩展方法可以处理获取描述属性 view code。
我一直希望做这样的事情
var elements = System.Enum.GetElements(CourseGrades);
var dict = new Dictionary<CourseGrades, string>();
foreach (var element in elements) {
dict.Add(element, element.GetDescription());
}
但我开始认为这样的事情是不可能做到的。
我一直在努力避免暴力破解
private Dictionary<CourseGrades, string> _courseGradesWithCaption = null;
public Dictionary < CourseGrades, string > CourseGradesWithCaptions
{
get
{
if ( _courseGradesWithCaption == null )
_courseGradesWithCaption = new Dictionary < CourseGrades, string > ()
{
{ CourseGrades.A, CourseGrades.A.GetDescription () }
, { CourseGrades.AMinus, CourseGrades.AMinus.GetDescription () }
, { CourseGrades.BPlus, CourseGrades.BPlus.GetDescription () }
// ... snip ...
};
return _courseGradesWithCaption;
}
}
我以为我借用了上面链接的扩展方法如何通过枚举
public static class EnumerationCaptionsBuilder
{
public static Dictionary < T, string > BuildCaptions<T> ( T e ) where T : IConvertible
{
if (!(e is System.Enum)) throw new ArgumentException("e is expected to be an enumeration.");
var type = e.GetType ();
var values = System.Enum.GetValues ( type );
var dict = new Dictionary<T, string> ();
foreach ( var val in values )
{
if ( (int) val != e.ToInt32 ( CultureInfo.InvariantCulture ) ) continue;
var enumElement = type.GetMember ( type.GetEnumName ( val ) ?? throw new InvalidOperationException ());
dict.Add(enumElement, enumElement.GetDescription());
}
}
}
但那时我才知道 type.GetMember
return 是一个 MemberInfo 对象,这不是我要找的对象。
有没有办法做我想做的事情,或者我只是在树上狂吠?
我不完全明白为什么你的扩展不适合你(如果你在 Enum 上有它,你的 "requested" 代码应该可以工作)。
下面是我的做法:
public static class EnumerationExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
public static IEnumerable<TEnum> GetEnumCollection<TEnum>(bool skipFirst = false)
{
var result = new List<TEnum>();
var enums = Enum.GetValues(typeof(TEnum));
for (int i = 0; i < enums.Length; i++)
{
if (skipFirst && i == 0) continue; //Some enums use "Invalid" or "Default" as first value
TEnum e = (TEnum)enums.GetValue(i);
result.Add(e);
}
return result;
}
}
此外,需要考虑的一件事是您为什么需要它。如果这是为了显示目的,也许 IValueConverter 是您应该做的。这允许您拥有枚举类型的集合,然后在 IValueConverter 对象接收枚举然后 returns .Description 扩展调用时非常容易地显示描述。
我提供的示例有一个 "skipFirst" 默认为 false,因为当我进行枚举时,我经常先放置一个无效的状态(例如 Default、Undefined 等)以确保默认状态无效(我想要以确保已设置某些内容而不是使用默认值)。
编辑
添加我使用过的 IValueConverter。
public class EnumerationToDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var casted = value as Enum;
return casted?.GetDescription();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//we have no need to get from visual descirption to the enumeration at this time.
throw new NotImplementedException();
}
}
然后你只需要将你的转换器实例化为一个带有键的资源并引用它。
<converters:EnumerationToDescriptionConverter x:Key="EnumerationToDescriptionConverter" />
<TextBlock Text="{Binding Converter={StaticResource EnumerationToDescriptionConverter}}"/>
在我的例子中,TextBlock 位于用于 ItemsControl 的 DataTemplate 中,该 ItemsControl 绑定到通过上面发布的其他扩展方法检索的枚举集合。
我有枚举元素和描述属性的枚举
public enum CourseGrades
{
[Description("A")]
A = 11,
[Description("A-")]
AMinus = 10,
[Description("B+")]
BPlus = 9,
[Description("B")]
B = 8,
[Description("B-")]
BMinus = 7,
[Description("C+")]
CPlus = 6,
[Description("C")]
C = 5,
[Description("C-")]
CMinus = 4,
[Description("D+")]
DPlus = 3,
[Description("D")]
D = 2,
[Description("D-")]
DMinus = 1,
[Description("E")]
E = 0,
[Description("Audit")]
AU = -1,
[Description("Incomplete")]
IC = -2,
[Description("Withdrawl")]
WD = -3,
[Description("Not Applicable")]
NA = -4
}
我的问题是我正在尝试建立一个描述列表,但我对如何做到这一点感到困惑。我看到的所有答案都说使用 Enum.GetNames()
或 Enum.GetValues()
我知道该怎么做。
这两个的问题是它们 return 一个字符串数组,它丢失了关于它来自哪里的所有上下文,所以我无法按照它来获取特定枚举值的描述我想要的。
我现在获取描述的方法是调用 CourseGrades.A.GetDescription()
,因为我有一个扩展方法可以处理获取描述属性 view code。
我一直希望做这样的事情
var elements = System.Enum.GetElements(CourseGrades);
var dict = new Dictionary<CourseGrades, string>();
foreach (var element in elements) {
dict.Add(element, element.GetDescription());
}
但我开始认为这样的事情是不可能做到的。
我一直在努力避免暴力破解
private Dictionary<CourseGrades, string> _courseGradesWithCaption = null;
public Dictionary < CourseGrades, string > CourseGradesWithCaptions
{
get
{
if ( _courseGradesWithCaption == null )
_courseGradesWithCaption = new Dictionary < CourseGrades, string > ()
{
{ CourseGrades.A, CourseGrades.A.GetDescription () }
, { CourseGrades.AMinus, CourseGrades.AMinus.GetDescription () }
, { CourseGrades.BPlus, CourseGrades.BPlus.GetDescription () }
// ... snip ...
};
return _courseGradesWithCaption;
}
}
我以为我借用了上面链接的扩展方法如何通过枚举
public static class EnumerationCaptionsBuilder
{
public static Dictionary < T, string > BuildCaptions<T> ( T e ) where T : IConvertible
{
if (!(e is System.Enum)) throw new ArgumentException("e is expected to be an enumeration.");
var type = e.GetType ();
var values = System.Enum.GetValues ( type );
var dict = new Dictionary<T, string> ();
foreach ( var val in values )
{
if ( (int) val != e.ToInt32 ( CultureInfo.InvariantCulture ) ) continue;
var enumElement = type.GetMember ( type.GetEnumName ( val ) ?? throw new InvalidOperationException ());
dict.Add(enumElement, enumElement.GetDescription());
}
}
}
但那时我才知道 type.GetMember
return 是一个 MemberInfo 对象,这不是我要找的对象。
有没有办法做我想做的事情,或者我只是在树上狂吠?
我不完全明白为什么你的扩展不适合你(如果你在 Enum 上有它,你的 "requested" 代码应该可以工作)。
下面是我的做法:
public static class EnumerationExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
public static IEnumerable<TEnum> GetEnumCollection<TEnum>(bool skipFirst = false)
{
var result = new List<TEnum>();
var enums = Enum.GetValues(typeof(TEnum));
for (int i = 0; i < enums.Length; i++)
{
if (skipFirst && i == 0) continue; //Some enums use "Invalid" or "Default" as first value
TEnum e = (TEnum)enums.GetValue(i);
result.Add(e);
}
return result;
}
}
此外,需要考虑的一件事是您为什么需要它。如果这是为了显示目的,也许 IValueConverter 是您应该做的。这允许您拥有枚举类型的集合,然后在 IValueConverter 对象接收枚举然后 returns .Description 扩展调用时非常容易地显示描述。
我提供的示例有一个 "skipFirst" 默认为 false,因为当我进行枚举时,我经常先放置一个无效的状态(例如 Default、Undefined 等)以确保默认状态无效(我想要以确保已设置某些内容而不是使用默认值)。
编辑 添加我使用过的 IValueConverter。
public class EnumerationToDescriptionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var casted = value as Enum;
return casted?.GetDescription();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//we have no need to get from visual descirption to the enumeration at this time.
throw new NotImplementedException();
}
}
然后你只需要将你的转换器实例化为一个带有键的资源并引用它。
<converters:EnumerationToDescriptionConverter x:Key="EnumerationToDescriptionConverter" />
<TextBlock Text="{Binding Converter={StaticResource EnumerationToDescriptionConverter}}"/>
在我的例子中,TextBlock 位于用于 ItemsControl 的 DataTemplate 中,该 ItemsControl 绑定到通过上面发布的其他扩展方法检索的枚举集合。