반사로 유형의 모든 상수를 얻으려면 어떻게해야합니까?


답변:


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 은 심지어 두 번째 줄을 통과하기 전이었습니다. 디자인 의도의 목적으로 모든 단계를 거치는 것을 발견했습니다 ...! 이는 SO 하나는 배울 필요가있을 때 중요합니다. 나는 당신의 경험이있는 모든 사람들이 당신이 여기에서 한 것처럼하기를 바랍니다.
LoneXcoder

4
IsLiteral 및 IsInitOnly와 관련된 주장에 대해 잘 모르겠습니다. 테스트 할 때 정적 읽기 전용 속성의 경우 IsLiteral은 항상 false 인 것 같습니다. 따라서 IsLiteral은 상수를 찾기 위해 확인 해야하는 유일한 플래그이므로 IsInitOnly를 무시할 수 있습니다. 다른 필드 유형 (예 : String, Int32)을 사용하여 이것이 차이가 있었는지 확인했지만 시도하지 않았습니다.
Mark Watts

49
또한 FieldInfo에서 const 값을 가져 오려면 GetRawConstantValue ()를 사용하십시오.
Sam Sippe

@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();않습니까?
T-moty

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
분명히 이것은 타입의 상수가 모두 문자열
이라면

왜 (a)는 메소드가 리턴하도록 (b)의 방법은 일반적인하지 IEnumerable<T>대신의 IList?
Wai Ha Lee

@WaiHaLee-완료 :-). 분명히 그것은 여전히 ​​문제의 클래스에있는 모든 타입의 const가 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.