按声明顺序对枚举进行排序

public enum CurrencyId { USD = 840, UAH = 980, RUR = 643, EUR = 978, KZT = 398, UNSUPPORTED = 0 } 

有没有办法对Enum.GetValues(typeof(CurrencyId)).Cast()结果进行排序Enum.GetValues(typeof(CurrencyId)).Cast()按顺序转换Enum.GetValues(typeof(CurrencyId)).Cast()它们是在.cs文件(USD,UAH,RUR,EUR,KZT,UNSUPPORTED)中声明的,而不是它们的底层代码? 就个人而言,我认为答案是’不’,因为原始订单在二进制文件中丢失了,所以…我该如何实现任务?

这是包含自定义属性的版本:

 [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] public class EnumOrderAttribute : Attribute { public int Order { get; set; } } public static class EnumExtenstions { public static IEnumerable GetWithOrder(this Enum enumVal) { return enumVal.GetType().GetWithOrder(); } public static IEnumerable GetWithOrder(this Type type) { if (!type.IsEnum) { throw new ArgumentException("Type must be an enum"); } // caching for result could be useful return type.GetFields() .Where(field => field.IsStatic) .Select(field => new { field, attribute = field.GetCustomAttribute() }) .Select(fieldInfo => new { name = fieldInfo.field.Name, order = fieldInfo.attribute != null ? fieldInfo.attribute.Order : 0 }) .OrderBy(field => field.order) .Select(field => field.name); } } 

用法:

 public enum TestEnum { [EnumOrder(Order=2)] Second = 1, [EnumOrder(Order=1)] First = 4, [EnumOrder(Order=3)] Third = 0 } var names = typeof(TestEnum).GetWithOrder(); var names = TestEnum.First.GetWithOrder(); 

简答:

 foreach(FieldInfo fi in typeof(CurrencyId).GetFields() .Where(fi => fi.IsStatic).OrderBy(fi => fi.MetadataToken)) Console.WriteLine(fi.Name); 

原因:

 public enum EnumOrder { Bad = -1, Zero = 0, One = 1 } public class ClassOrder { public int first; public int First { get { return first; } } public int second; public int Second { get { return second; } } } private void PrintInfos(string head, IEnumerable list) where T: MemberInfo { memo.AppendText(string.Format(" {0}: ", head)); bool first = true; foreach(var e in list) { if(first) first = false; else memo.AppendText(", "); memo.AppendText(e.Name); } memo.AppendText("\r\n"); } private void ReflectionOrderTest(object sender, EventArgs e) { typeof(EnumOrder).GetField("One"); typeof(ClassOrder).GetField("second"); typeof(ClassOrder).GetProperty("Second"); memo.AppendLine("First time order:"); PrintInfos("Enum", typeof(EnumOrder).GetFields().Where(fi => fi.IsStatic)); PrintInfos("Fields", typeof(ClassOrder).GetFields()); PrintInfos("Properties", typeof(ClassOrder).GetProperties()); PrintInfos("Members", typeof(ClassOrder).GetMembers()); memo.AppendLine("Broken order:"); PrintInfos("Enum", typeof(EnumOrder).GetFields().Where(fi => fi.IsStatic)); PrintInfos("Fields", typeof(ClassOrder).GetFields()); PrintInfos("Properties", typeof(ClassOrder).GetProperties()); PrintInfos("Members", typeof(ClassOrder).GetMembers()); memo.AppendLine("MetadataToken Sorted:"); PrintInfos("Enum", typeof(EnumOrder).GetFields().Where(fi => fi.IsStatic).OrderBy(fi => fi.MetadataToken)); PrintInfos("Fields", typeof(ClassOrder).GetFields().OrderBy(fi => fi.MetadataToken)); PrintInfos("Properties", typeof(ClassOrder).GetProperties().OrderBy(fi => fi.MetadataToken)); PrintInfos("Members", typeof(ClassOrder).GetMembers().OrderBy(fi => fi.MetadataToken)); } 

输出:

第一次订购:
   Enum:坏,零,一
  领域:第一,第二
  属性:第一,第二
  成员:get_First,get_Second,ToString,Equals,GetHashCode,GetType,.ctor,Second,First,second,first
订单破损:
   Enum:One,Bad,Zero
  领域:第二,第一
  属性:第二,第一
  成员:get_Second,get_First,ToString,Equals,GetHashCode,GetType,.ctor,Second,First,second,first
 MetadataToken已排序:
   Enum:坏,零,一
  领域:第一,第二
  属性:第一,第二
  成员:第一,第二,ToString,Equals,GetHashCode,GetType,get_First,get_Second,.ctor,First,Second

重要说明:自.NET 2.0以来, MemberInfo.GetFields()得到一些缓存的支持(阅读关于它的这篇文章 )并且可能不会按照声明的顺序返回字段(更准确地说:编译器发出的顺序似乎保留了顺序一个文件,但合并的partial class顺序是未定义的)。 这是关于stackoverflow的类似问题 ,Marc Gravell的一条评论是:

10.2.6成员[…]类型中成员的排序对C#代码来说很少有意义,但在与其他语言和环境交互时可能很重要。 在这些情况下,未定义在多个部分中声明的类型内的成员的顺序。

这样做应该克服缓存的问题:

 GC.Collect(); GC.WaitForPendingFinalizers(); var fields = typeof(Whatever).GetFields(); 

按MetadataToken排序也可能有所帮助。 没有找到保证,但这应该提供很好的理由为什么它应该工作:

较低的三个字节(称为记录标识符(RID))包含令牌的MSB引用的元数据表中的行的索引。 例如,值为0x02000007的元数据标记引用当前范围中TypeDef表中的第7行。 类似地,令牌0x0400001A引用当前作用域中FieldDef表中的第26行(十进制)。

原始答案:使用typeof(CurrencyId).GetFields() ,检查FieldInfo.IsStatic (一个__value不会),然后根据需要使用FieldInfo.NameGetValue

链接到IDEONE: http ://ideone.com/hnT6YL

 using System; using System.Reflection; public class Test { public enum CurrencyId { USD = 840, UAH = 980, RUR = 643, EUR = 978, KZT = 398, UNSUPPORTED = 0 } public static void Main() { foreach(FieldInfo fi in typeof(CurrencyId).GetFields()) if(fi.IsStatic) Console.WriteLine(fi.Name); } } 

输出:

 USD UAH RUR EUR KZT UNSUPPORTED 

编辑: 订单不保证: ( (见评论)

GetFields方法不按特定顺序返回字段,例如按字母顺序或声明顺序。 您的代码不得依赖于返回字段的顺序,因为该顺序会有所不同。

这可能是.NET 4.5的解决方案

 using System; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)] public sealed class OrderAttribute : Attribute { private readonly int order_; public OrderAttribute( [CallerLineNumber] int order = 0) { order_ = order; } public int Order { get { return order_; } } } public class Test { public enum CurrencyId { [Order] USD = 840, [Order] UAH = 980, [Order] RUR = 643, [Order] EUR = 978, [Order] KZT = 398, [Order] UNSUPPORTED = 0 } public static void Main() { foreach(FieldInfo fi in typeof(CurrencyId).GetFields() .Where(fi => fi.IsStatic) .OrderBy(fi => ((OrderAttribute)fi.GetCustomAttributes( typeof(OrderAttribute), true)[0]).Order)) Console.WriteLine(fi.GetValue(null).ToString()); } }