[英]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.