使用反射获取和保存枚举

Get and save enum using reflection

我有一个项目,其中有一些程序集实现了抽象 class。

每个程序集都有一个名为 ResultEnum 的 public 枚举。 此 ResultEnum 的值作为 int 存储在数据库中。

我有另一个显示一些信息的 Web 项目,我希望它也显示此 int 的字符串表示形式 - 来自 ResultEnum 的相应值的名称。

我想做的是,使用 MEF,加载所有相关的程序集(这里没问题),使用反射搜索这个枚举(这里也没有问题),然后以某种方式存储枚举,并缓存它是为了避免下一次我想将 int 从数据库转换为字符串表示形式(如果需要的话,反过来),因为我的数据库中有几千条记录 table.

AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(path));
_container = new CompositionContainer(catalog);

try
{
    _container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
    Console.WriteLine(compositionException.ToString());
}

foreach (var task in myTasks)
{
    TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;

    MemberInfo[] infos = instance.GetType().GetMembers(BindingFlags.Public | BindingFlags.Static);
    foreach (MemberInfo member in infos.Where(x => x.Name.Equals("ResultEnum")))
    {
        Console.WriteLine(member);                    
    }
}

你建议下一步应该做什么? 我应该怎么store/cache呢?

谢谢

来自您的评论:

I agree, But question is how do I iterate over the values and names of the enumerator

我假设你的意思是 "enumeration",而不是 "enumerator"。您可以使用 Enum.GetValues 方法:

var valuesToNames =
    Enum.GetValues(enumType)
        .Cast<object>()
        .ToDictionary(o => (int)o, o => Enum.GetName(enumType, o));

And, is there a better solution than a dictionary

如何更好?我认为字典是一个很好的解决方案;你有什么理由想要别的东西吗?

除了@Thomas的回答:

由于使用反射,您可以从 属性 中获取精确的 int 值,可以使用下一个表达式获取该具体值的名称:

var enumValueName = Enum.GetName(member.GetType(), member.GetValue(instance));

UPD

我真的很想念你反映 MemberInfos。要应用我的解决方案,您可以通过以下方式更新您的反思:

foreach (var task in myTasks)
{
    TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;

// Reflect properties, not all members
    PropertyInfo[] infos = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static);
    foreach (PropertyInfo prop in infos.Where(x => x.Name.Equals("ResultEnum")))
    {
        var enumValueName = Enum.GetName(prop.GetType(), prop.GetValue(instance));                  
    }
}

或者您可以将 MemberInfo 转换为 PropertyInfo。

解决此问题的一种方法是考虑使用子class可用枚举技术(有时也称为多态枚举)。

我写了几个通用的 classes 专门支持这些类型,你可以阅读 here. Also, a proposal 已提交给 Roslyn 编译器团队 Github 添加支持这些类型的 C# 枚举。

下面是一组子class可用枚举的示例,这些枚举具有两种基础类型,字符串和整数,使用我项目中的 classes:

public sealed class Status : StringIntegerEnum<Status>
{
    public static readonly Status Active = new Status("active", 1);
    public static readonly Status Inactive = new Status("inactive", 0);

    private Status(string status, int statusCode) : base(status, statusCode) {}
}

请注意,字符串值 与常量名称本身不同,这允许您使用违反 C# 中正常命名约定的字符的基础字符串值。

StringIntegerEnum<tStringIntegerEnum> 基础 class 提供了 .AllValues.AllNaturalValues.AllStringValues 静态方法,您可以使用它们来枚举枚举值列表或两者兼而有之他们潜在价值的类型。

这就是我最终编写代码的方式:

        resultEnumsForTasks = new Dictionary<string, Dictionary<UInt16, string>>();
        foreach (var task in myTasks)
        {
            Dictionary<UInt16, string> _enum =  new Dictionary<UInt16,string>();
            TaskAbstract instance = (TaskAbstract)task.CreateExport().Value;
            MemberInfo resultEnum = instance.GetType().GetMember("ResultEnum").FirstOrDefault();
            if (resultEnum == null)
                continue;

            string[] names = Enum.GetNames(resultEnum as Type);
            IList<int> vals = (IList<int>)Enum.GetValues(resultEnum as Type);
            for (int i = 0; i < names.Length; i++)
            {
                _enum.Add(Convert.ToUInt16(vals[i]), names[i]);
            }
            resultEnumsForTasks.Add(instance.GetType().Name, _enum);
        }

它与@n.turakulov 的解决方案非常相似,但是他的解决方案对我不起作用,因为出于某种原因我得到了一个空的 PropertyInfo 列表...

感谢所有提供帮助的人!