リフレクションによって型のすべての定数を取得するにはどうすればよいですか?


回答:


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

または1行で:

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

13
私の+1は、2行目を通過する前でもありました。設計目的によるすべてのステップを実行していることに気づきました。これは、そこから学ぶ必要があるときにとても重要です。私はあなたがここでしたようにあなたの経験を持つすべての人がしてくれることを願っています。
LoneXcoder

4
IsLiteralとIsInitOnlyに関するアサーションについてはわかりません。テストでは、静的な読み取り専用プロパティの場合、IsLiteralは常にfalseであるように見えます。したがって、IsLiteralは、定数を見つけるために確認する必要がある唯一のフラグであり、IsInitOnlyを無視できます。さまざまなフィールドタイプ(たとえば、String、Int32)を試して、これが違いを生むかどうかを確認しましたが、違いはありませんでした。
マークワッツ

49
また、FieldInfoからconstの値を取得するには、GetRawConstantValue()を使用します。
Sam Sippe 2015

@MarkWattsは正しいです。これが投稿されてから動作が変更された可能性があります。いずれにせよ、IsLiteralsaysのドキュメントは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();ですか?
T-moty 2018年

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>代わりにメソッドを返さないのはIListなぜですか?
Wai Ha Lee

@WaiHaLee-完了:-)。明らかにそれはまだ問題のクラスにconstsのすべてのタイプを想定していますが、型Tである
bytedev

2

property.GetConstantValue()値を取得するために使用します。


1
それはあなたプロパティを持っている場合にも当てはまるかもしれません-しかし、どのように最初にプロパティを取得しますか?
Wai Ha Lee

4
.Net 4.5の場合:GetRawConstantValue()
Chris
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.