2012-04-21 70 views

回答

168

虽然这是一个旧的代码:

private FieldInfo[] GetConstants(System.Type type) 
{ 
    ArrayList constants = new ArrayList(); 

    FieldInfo[] fieldInfos = type.GetFields(
     // Gets all public and static fields 

     BindingFlags.Public | BindingFlags.Static | 
     // This tells it to get the fields from all base types as well 

     BindingFlags.FlattenHierarchy); 

    // Go through the list and only pick out the constants 
    foreach(FieldInfo fi in fieldInfos) 
     // IsLiteral determines if its value is written at 
     // compile time and not changeable 
     // IsInitOnly determine if the field can be set 
     // in the body of the constructor 
     // for C# a field which is readonly keyword would have both true 
     // but a const field would have only IsLiteral equal to true 
     if(fi.IsLiteral && !fi.IsInitOnly) 
      constants.Add(fi);   

    // Return an array of FieldInfos 
    return (FieldInfo[])constants.ToArray(typeof(FieldInfo)); 
} 

Source

您可以轻松地将其转换为更清晰的代码使用泛型和LINQ:

private List<FieldInfo> GetConstants(Type type) 
{ 
    FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Public | 
     BindingFlags.Static | BindingFlags.FlattenHierarchy); 

    return fieldInfos.Where(fi => fi.IsLiteral && !fi.IsInitOnly).ToList(); 
} 

或用一条线:

type.GetFields(BindingFlags.Public | BindingFlags.Static | 
       BindingFlags.FlattenHierarchy) 
    .Where(fi => fi.IsLiteral && !fi.IsInitOnly).ToList(); 
+9

*我+ 1 *被在我甚至通过第二条线之前......我注意到你正在经历每一步......以意向为目的的设计目的......!当人们需要从中吸取教训时,这很重要。我希望每个有你的经验的人都能像你这样做。 – LoneXcoder 2012-12-10 08:49:16

+3

我不确定关于IsLiteral和IsInitOnly的断言。在测试看来,对于静态只读属性IsLiteral总是假 - 因此IsLiteral是唯一需要检查以查找常量的标志,并且您可以忽略IsInitOnly。我尝试过使用不同的字段类型(例如String,Int32)来查看这是否有所作为,但没有。 – 2015-05-05 09:55:02

+29

此外,要从FieldInfo获取const的值,请使用GetRawConstantValue()。 – 2015-07-07 00:15:48

1

使用property.GetConstantValue()来获得价值

+0

当你拥有房产时,情况可能就是这样 - 但是,你是如何获得房产的? – 2015-12-14 10:15:11

+1

在.Net 4.5中它是:'GetRawConstantValue()' – Chris 2016-03-11 20:16:03

10

为类型的扩展名:

public static class TypeExtensions 
{ 
    public static IEnumerable<FieldInfo> GetConstants(this Type type) 
    { 
     var fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); 

     return fieldInfos.Where(fi => fi.IsLiteral && !fi.IsInitOnly); 
    } 

    public static IEnumerable<T> GetConstantsValues<T>(this Type type) where T : class 
    { 
     var fieldInfos = GetConstants(type); 

     return fieldInfos.Select(fi => fi.GetRawConstantValue() as T); 
    } 
} 
+0

显然这是如果你的常量在类型上都是字符串;-) – nashwan 2015-12-11 16:57:36

+0

为什么不能(a)使方法成为通用的,(b)使方法返回'IEnumerable '而不是“IList”? – 2015-12-11 17:06:05

+0

@WaiHaLee - 完成:-)。尽管显然它仍然假定所讨论的类中的所有类型的常量类型都是T. – nashwan 2015-12-14 10:23:57

16

如果你想获得的值的特定类型的所有常量,从目标类型,在这里是一个扩展方法(此页面上延伸一些问题的答案):

public static class TypeUtilities 
{ 
    public static List<T> GetAllPublicConstantValues<T>(this Type type) 
    { 
     return type 
      .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) 
      .Where(fi => fi.IsLiteral && !fi.IsInitOnly && fi.FieldType == typeof(T)) 
      .Select(x => (T)x.GetRawConstantValue()) 
      .ToList(); 
    } 
} 

然后,对于一类这样

static class MyFruitKeys 
{ 
    public const string Apple = "apple"; 
    public const string Plum = "plum"; 
    public const string Peach = "peach"; 
    public const int WillNotBeIncluded = -1; 
} 

您可以获取string常数值如下:

List<string> result = typeof(MyFruitKeys).GetAllPublicConstantValues<string>(); 
//result[0] == "apple" 
//result[1] == "plum" 
//result[2] == "peach" 
相关问题