2012-04-21 14 views

Respuesta

168

Aunque se trata de un código antiguo:

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

usted puede convertir fácilmente a más limpias que utilizan los genéricos de código y 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(); 
} 

O con una línea:

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

* Mi + 1 * era incluso antes de pasar por la segunda línea ... noté que estás atravesando cada paso con su ... propósito previsto por diseño ...! esto es ** SO ** importante cuando uno necesita aprender de ello. quisiera que cada uno con tu experiencia hiciera lo que hiciste aquí. – LoneXcoder

+3

No estoy seguro acerca de las afirmaciones con respecto a IsLiteral e IsInitOnly. En las pruebas parecería que para las propiedades estáticas de solo lectura IsLiteral siempre es falso, por lo que IsLiteral es el único indicador que debe verificar para encontrar las constantes y puede ignorar IsInitOnly. Intenté con diferentes tipos de campos (por ejemplo, String, Int32) para ver si esto hacía alguna diferencia, pero no fue así. –

+29

Además, para obtener el valor de const de FieldInfo, use GetRawConstantValue(). –

1

uso property.GetConstantValue() para obtener el valor

+0

Ese puede ser el caso cuando * tiene * la propiedad, pero * ¿cómo * obtiene primero la propiedad? –

+1

En .Net 4.5 es: 'GetRawConstantValue()' – Chris

10

Como extensiones Tipo:

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

Obviamente, esto es si sus constantes en un tipo son todas las cadenas ;-) – nashwan

+0

¿Por qué no (a) hacer los métodos genéricos, (b) hacer que los métodos devuelvan 'IEnumerable ' en lugar de un 'IList'? –

+0

@WaiHaLee - Hecho :-). Aunque obviamente asume que todos los tipos de constelaciones en la clase en cuestión son de tipo T. – nashwan

16

Si desea obtener los valores de todas las constantes de un tipo específico, desde el tipo de destino, aquí es un método de extensión (que se extiende algunas de las respuestas en esta página):

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(); 
    } 
} 

Entonces, para una clase como esta

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

puede obtener el string valores constantes como esto:

List<string> result = typeof(MyFruitKeys).GetAllPublicConstantValues<string>(); 
//result[0] == "apple" 
//result[1] == "plum" 
//result[2] == "peach" 
Cuestiones relacionadas