Bir türdeki tüm sabitleri yansıtarak nasıl elde edebilirim?


Yanıtlar:


265

Eski bir kod olmasına rağmen:

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

Kaynak

Jenerikler ve LINQ kullanarak kolayca daha temiz bir koda dönüştürebilirsiniz:

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

Veya bir satırla:

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

13
+ 1'im, hatta 2. çizgiyi geçmeden önceydi .. tasarım adımıyla ... her adımı attığınızı fark ettim! bu SO biri ondan öğrenmeye ihtiyacı olduğunda önemli. keşke burada yaptığınız gibi deneyiminizle her birini yapardı.
LoneXcoder

4
IsLiteral ve IsInitOnly ile ilgili iddialardan emin değilim. Test sırasında statik salt okunur özellikler için IsLiteral her zaman yanlıştır - bu nedenle IsLiteral sabitleri bulmak için kontrol etmeniz gereken tek bayraktır ve IsInitOnly'ı yok sayabilirsiniz. Farklı alan türleri (örneğin, String, Int32) ile bu herhangi bir fark yaptığını görmek için çalıştı ama olmadı.
Mark Watts

49
Ayrıca, const değerini FieldInfo'dan almak için GetRawConstantValue () kullanın.
Sam Sippe

@MarkWatts doğru. Bu yayınlandığından beri davranış değişmiş olabilir. Her durumda IsLiteraldiyor if its value is written at compile timeve bu sadece sabitler için geçerlidir, bu şu anda böyle davranıyor (.NET 4.5.2 itibariyle test edilmiştir)
nawfal

52

Eğer almak istiyorsanız değerleri hedef türünden, belirli bir türdeki tüm sabitler, burada bir uzantısı yöntemi (bu sayfadaki bazı yanıtlar uzanan) 'dir:

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

Sonra böyle bir sınıf için

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

Bunun stringgibi sabit değerleri elde edebilirsiniz :

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

Neden bu: .Where(fi => fi.IsLiteral && !fi.IsInitOnly).Select(x => x.GetRawConstantValue()).OfType<T>().ToList();?
T-moty

17

Tür uzantıları olarak:

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
Açıkçası bu, bir türdeki sabitleriniz tüm dizeler ise ;-)
bytedev

Neden (a) yöntemleri genel yapmıyoruz, (b) yöntemleri bir IEnumerable<T>yerine döndürmüyor IList?
Wai Ha Lee

@WaiHaLee - Tamamlandı :-). Açıkçası, yine de söz konusu sınıftaki tüm türlerin T tipi olduğunu varsayar.
bytedev

2

property.GetConstantValue()Değer almak için kullanın .


1
Eğer o zaman iyi durumda olabilir var özelliğine - ama nasıl ilk özelliği alabilirim?
Wai Ha Lee

4
Net GetRawConstantValue()
Chris
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.