Як я можу отримати відображення всіх констант типу?


Відповіді:


264

Хоча це старий код:

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

Джерело

Ви можете легко перетворити його в чистіший код, використовуючи дженерики та 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();

13
Мій +1 був ще до того, як я навіть пройшов другий рядок .. я помітив, що ви проходите кожен крок зі своєю ... задуманою метою дизайну ...! це ТАК важливо, коли потрібно з цього вчитися. Я хочу, щоб кожен із своїм досвідом робив так, як ви робили тут.
LoneXcoder

4
Я не впевнений у твердженнях щодо IsLiteral та IsInitOnly. Під час тестування здавалося б, що для статичних властивостей для читання лише IsLiteral завжди хибний - тому IsLiteral - єдиний прапор, який потрібно перевірити, щоб знайти константи, і ви можете ігнорувати IsInitOnly. Я спробував з різними типами полів (наприклад, String, Int32), щоб побачити, чи це мало значення, але це не так.
Марк Ваттс

49
Крім того, щоб отримати значення const з FieldInfo, використовуйте GetRawConstantValue ().
Сем Сіппе

@MarkWatts має рацію. Можливо, поведінка змінилася з моменту публікації цього повідомлення. У будь-якому випадку документація IsLiteralговорить if its value is written at compile timeі це справедливо лише для констант, як це поводиться зараз (перевірено станом на .NET 4.5.2)
nawfal

52

Якщо ви хочете отримати значення всіх констант певного типу, від цільового типу, ось метод розширення (розширення деяких відповідей на цій сторінці):

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"

Чому б не так .Where(fi => fi.IsLiteral && !fi.IsInitOnly).Select(x => x.GetRawConstantValue()).OfType<T>().ToList();:?
Т-моти

17

Як розширення типу:

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

1
Очевидно, що це якщо ваші константи на типі - це всі рядки ;-)
bytedev

Чому б не (a) зробити методи загальними, (b) зробити так, щоб методи поверталися IEnumerable<T>замість an IList?
Вай Ха Лі

@WaiHaLee - Готово :-). Хоча, очевидно, він все ще передбачає, що всі типи змагань на розглянутому класі мають тип Т.
bytedev

2

Використовуйте property.GetConstantValue()для отримання вартості.


1
Це може бути випадок, коли у вас є майно - але як ви спочатку отримаєте майно?
Вай Ха Лі

4
В .Net 4.5 це:GetRawConstantValue()
Кріс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.