【问题标题】:How can I get all constants of a type by reflection?如何通过反射获得一个类型的所有常量?
【发布时间】:2012-05-02 23:01:50
【问题描述】:

如何使用反射获得任何类型的所有常量?

【问题讨论】:

标签: c# .net reflection constants


【解决方案1】:

虽然是旧代码:

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

Source

您可以使用泛型和 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();

【讨论】:

  • 我的 +1 甚至在我通过第二行之前 ..我注意到你正在经历每一步 ... !当人们需要从中学习时,这一点SO很重要。我希望每个有你经验的人都能像你在这里所做的那样。
  • 我不确定有关 IsLiteral 和 IsInitOnly 的断言。在测试中,对于静态只读属性,IsLiteral 似乎总是错误的 - 所以 IsLiteral 是您需要检查以查找常量的唯一标志,您可以忽略 IsInitOnly。我尝试使用不同的字段类型(例如 String、Int32)来查看这是否有任何区别,但没有。
  • 另外,要从 FieldInfo 中获取 const 的值,请使用 GetRawConstantValue()。
  • @MarkWatts 是对的。可能是发布后行为发生了变化。在任何情况下,IsLiteral 的文档都说if its value is written at compile time,这仅适用于常量,这就是它现在的行为方式(从 .NET 4.5.2 开始测试)
【解决方案2】:

如果您想从目标类型中获取特定类型的所有常量的,这里有一个扩展方法(扩展本页的一些答案):

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 =&gt; fi.IsLiteral &amp;&amp; !fi.IsInitOnly).Select(x =&gt; x.GetRawConstantValue()).OfType&lt;T&gt;().ToList();
【解决方案3】:

作为类型扩展:

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

【讨论】:

  • 显然,如果您的类型上的常量都是字符串;-)
  • 为什么不 (a) 使方法通用,(b) 使方法返回 IEnumerable&lt;T&gt; 而不是 IList
  • @WaiHaLee - 完成:-)。尽管显然它仍然假设所讨论的类上的所有 const 类型都是 T 类型。
【解决方案4】:

使用property.GetConstantValue() 获取价值。

【讨论】:

  • 当您拥有房产时,很可能就是这种情况 - 但如何首先获得房产?
  • 在 .Net 4.5 中是:GetRawConstantValue()
【解决方案5】:
public class Constants
{
    public class InputType
    {
        public const string DOCUMENTPHOTO = "document-photo";
        public const string SELFIEPHOTO = "selfie-photo";
        public const string SELFIEVIDEO = "selfie-video";
        public static List<string> Domain { get { return typeof(Constants.InputType).GetAllPublicConstantValues<string>(); } }
    }
    public class Type
    {
        public const string DRIVINGLICENSE = "driving-license";
        public const string NATIONALID = "national-id";
        public const string PASSPORT = "passport";
        public const string PROOFOFRESIDENCY = "proof-of-residency";
        public static List<string> Domain { get { return typeof(Constants.Type).GetAllPublicConstantValues<string>(); } }
    }
    public class Page
    {
        public const string FRONT = "front";
        public const string BLACK = "back";
        public static List<string> Domain { get { return typeof(Constants.Page).GetAllPublicConstantValues<string>(); } }
    }
    public class FileType
    {
        public const string FRONT = "selfie";
        public const string BLACK = "video";
        public const string DOCUMENT = "document";
        public const string MEDIA = "media";
        public const string CAPTCHA = "captcha";
        public const string DIGITALSIGNATURE = "digitalSignature";
        public static List<string> Domain { get { return typeof(Constants.FileType).GetAllPublicConstantValues<string>(); } }
    }
}

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

使用:var inputTypeDomain = Constants.InputType.Domain;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 2010-09-09
    • 1970-01-01
    • 2023-04-04
    • 2013-04-02
    相关资源
    最近更新 更多