public enum CurrencyId
{
USD = 840,
UAH = 980,
RUR = 643,
EUR = 978,
KZT = 398,
UNSUPPORTED = 0
}
有没有办法按顺序对Enum.GetValues(typeof(CurrencyId)).Cast<CurrencyId>()
的结果进行排序?它们是在.cs文件(USD,UAH,RUR,EUR,KZT,UNSUPPORTED)中声明的,而不是它们的基础代码?就个人而言,我认为答案是“不”,因为原始订单在二进制文件中丢失了,所以...我该如何实现任务呢?
答案 0 :(得分:13)
以下是具有自定义属性的版本:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class EnumOrderAttribute : Attribute
{
public int Order { get; set; }
}
public static class EnumExtenstions
{
public static IEnumerable<string> GetWithOrder(this Enum enumVal)
{
return enumVal.GetType().GetWithOrder();
}
public static IEnumerable<string> 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<EnumOrderAttribute>()
})
.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();
答案 1 :(得分:5)
简答:
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<T>(string head, IEnumerable<T> 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));
}
<强> 输出: 强>
First time order: Enum: Bad, Zero, One Fields: first, second Properties: First, Second Members: get_First, get_Second, ToString, Equals, GetHashCode, GetType, .ctor, Second, First, second, first Broken order: Enum: One, Bad, Zero Fields: second, first Properties: Second, First Members: get_Second, get_First, ToString, Equals, GetHashCode, GetType, .ctor, Second, First, second, first MetadataToken Sorted: Enum: Bad, Zero, One Fields: first, second Properties: First, Second Members: first, second, ToString, Equals, GetHashCode, GetType, get_First, get_Second, .ctor, First, Second
重要说明: MemberInfo.GetFields()
由.NET 2.0(读取this nice post about it)后的某些缓存支持,并且可能不会返回声明的字段顺序(更准确地说:编译器发出的顺序似乎保留了一个文件中的顺序,但是未定义合并partial class
的顺序)。 Here is similar question on stackoverflow,Marc Gravell的一条评论写道:
10.2.6成员[...]类型中成员的排序对C#代码来说很少有意义,但在与C#代码接口时可能很重要 其他语言和环境。在这些情况下,订购 在多个部分中声明的类型中的成员是未定义的。
这样做可以解决缓存问题:
GC.Collect();
GC.WaitForPendingFinalizers();
var fields = typeof(Whatever).GetFields();
按MetadataToken排序也可能有所帮助。没有找到保证,但是this应该提供很好的理由为什么它应该有效:
低三个字节,称为记录标识符(RID), 包含元数据表中行的索引 令牌的MSB指的是。例如,带有值的元数据标记 0x02000007引用当前作用域中TypeDef表中的第7行。 类似地,令牌0x0400001A引用FieldDef中的第26行(十进制) 当前范围内的表。
原始答案:
使用typeof(CurrencyId).GetFields()
,检查FieldInfo.IsStatic
(一个__value
赢了),然后根据需要使用FieldInfo.Name
或GetValue
。
指向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
编辑: The order is not guaranteed :( (见评论)
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());
}
}