簡體   English   中英

使用反射獲取和保存枚舉

[英]Get and save enum using reflection

我有一個項目,其中有一些實現抽象類的程序集。

每個程序集都有一個名為ResultEnum的公共枚舉。 此ResultEnum的值以int形式存儲在數據庫中。

我有另一個顯示一些信息的Web項目,我希望它也顯示此int的字符串表示形式-ResultEnum中對應值的名稱。

我想做的是,使用MEF,加載所有相關程序集(這里沒有問題),使用反射搜索該枚舉(這里也沒有問題),然后以某種方式存儲該枚舉,並進行緩存以避免下次我想將int從數據庫轉換為字符串表示形式時(如果需要,也可以進行其他方法)將所有這些過程轉換,因為我的db表中有數千條記錄。

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

您認為下一步應該采取什么行動? 我應該如何存儲/緩存它?

謝謝

除了@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。

解決此問題的一種方法是考慮使用可歸類的枚舉技術(有時也稱為多態枚舉)。

我編寫了兩個通用類,專門支持這些類型的類型,您可以在此處閱讀。 另外,已經向Github上的Roslyn編譯器團隊提交了一份提案 ,以增加對C#中這些枚舉類型的支持。

這是使用我項目中的類的一組可子類枚舉的示例,這些枚舉具有兩個基礎類型,字符串和整數:

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>基類提供.AllValues.AllNaturalValues.AllStringValues靜態方法,可用於枚舉枚舉值列表或它們的兩種基礎值類型。

根據您的評論:

我同意,但是問題是我如何遍歷枚舉器的值和名稱

我假設您的意思是“枚舉”,而不是“枚舉”。 您可以使用Enum.GetValues方法:

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

而且,有沒有比字典更好的解決方案

更好嗎? 我認為字典是一個很好的解決方案。 有什么理由會讓您想要其他東西嗎?

這就是我最終編寫代碼的方式:

        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的空白列表...

感謝所有協助的人!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM