Short Answer:
foreach(FieldInfo fi in typeof(CurrencyId).GetFields()
.Where(fi => fi.IsStatic).OrderBy(fi => fi.MetadataToken))
Console.WriteLine(fi.Name);
Reason:
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));
}
Output:
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
IMPORTANT NOTES: MemberInfo.GetFields()
is backed by some cache since .NET 2.0 (read this nice post about it) and may not return the fields in declared order (more precisely: the order emited by compiler wich seems to preserve the order in one file, but order of merged partial class
is undefined). Here is similar question on stackoverflow, and one comment from Marc Gravell reads:
10.2.6 Members [...] The ordering of members within a type is rarely significant to C# code, but may be significant when interfacing with
other languages and environments. In these cases, the ordering of
members within a type declared in multiple parts is undefined.
Doing this should overcome the problem with the cache:
GC.Collect();
GC.WaitForPendingFinalizers();
var fields = typeof(Whatever).GetFields();
Sorting by MetadataToken may help as well. Didn't find a guarantee, but thisshould provide good reasoning why it should work:
The lower three bytes, referred to as the record identifier (RID),
contain the index of the row within the metadata table to which the
token's MSB refers. For example, the metadata token with value
0x02000007 refers to row 7 in the TypeDef table in the current scope.
Similarly, token 0x0400001A refers to row 26 (decimal) in the FieldDef
table in the current scope.
ORIGINAL ANSWER:
Use typeof(CurrencyId).GetFields()
, check for FieldInfo.IsStatic
(one __value
won't be), then use FieldInfo.Name
or GetValue
as needed.
Link to 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);
}
}
Output:
USD
UAH
RUR
EUR
KZT
UNSUPPORTED
EDIT: The order is not guaranteed :( (See comments)
The GetFields method does not return fields in a particular order,
such as alphabetical or declaration order. Your code must not depend
on the order in which fields are returned, because that order varies.
This may be solution for .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());
}
}