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


Відповіді:


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.