【发布时间】:2010-11-13 03:12:29
【问题描述】:
有没有办法将enum 转换为包含所有枚举选项的列表?
【问题讨论】:
-
我认为,如果您打算这样做,您可能想考虑是否真的应该使用枚举,或者是否应该切换到代表 w/e 您的枚举的对象。
-
检查这个答案也可能有用:stackoverflow.com/a/12022617/1830909
有没有办法将enum 转换为包含所有枚举选项的列表?
【问题讨论】:
这将返回一个枚举的所有值的IEnumerable<SomeEnum>。
Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();
如果您希望它成为List<SomeEnum>,只需在.Cast<SomeEnum>() 之后添加.ToList()。
要在数组上使用 Cast 函数,您需要在 using 部分中包含 System.Linq。
【讨论】:
var array = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToArray();Enum.GetValues 已经返回一个数组,所以你只需要做var values = (SomeEnum[])Enum.GetValues(typeof(SomeEnum))
Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().Cast<int>().ToList()
更简单的方法:
Enum.GetValues(typeof(SomeEnum))
.Cast<SomeEnum>()
.Select(v => v.ToString())
.ToList();
【讨论】:
ToList()?这比公认的答案容易得多?它和它一样,只是你最后转换为string。
Enum.GetNames(typeof(System.Net.HttpStatusCode)) 将获得 all 的 distinct 名称,而来自答案的方法将获得一些重复的字符串(因为 v.ToString() 将为每个重复的基础整数值)。见System.Net.HttpStatusCode enum documentation。
简短的回答是,使用:
(SomeEnum[])Enum.GetValues(typeof(SomeEnum))
如果你需要一个局部变量,它是var allSomeEnumValues = (SomeEnum[])Enum.GetValues(typeof(SomeEnum));。
为什么是这样的语法?!
static 方法 GetValues 是在旧的 .NET 1.0 时代引入的。它返回一个运行时类型为SomeEnum[] 的一维数组。但由于它是一种非泛型方法(直到 .NET 2.0 才引入泛型),它不能这样声明其返回类型(编译时返回类型)。
.NET 数组确实有一种协方差,但是因为SomeEnum 将是一个值类型,并且因为数组类型协方差不适用于值类型,他们甚至不能将返回类型声明为object[] 或Enum[]。 (这与例如 this overload of GetCustomAttributes from .NET 1.0 不同,它具有编译时返回类型 object[] 但实际上返回类型为 SomeAttribute[] 的数组,其中 SomeAttribute 必须是引用类型。)
因此,.NET 1.0 方法必须将其返回类型声明为System.Array。但我向你保证,它是SomeEnum[]。
每次使用相同的枚举类型再次调用GetValues 时,它都必须分配一个新数组并将值复制到新数组中。那是因为数组可能被方法的“消费者”写入(修改),所以他们必须创建一个新数组以确保值不变。 .NET 1.0 没有好的只读集合。
如果您需要许多不同位置的所有值的列表,请考虑只调用一次 GetValues 并将结果缓存在只读包装器中,例如:
public static readonly ReadOnlyCollection<SomeEnum> AllSomeEnumValues
= Array.AsReadOnly((SomeEnum[])Enum.GetValues(typeof(SomeEnum)));
那么你可以多次使用AllSomeEnumValues,同一个集合可以安全地重复使用。
为什么使用.Cast<SomeEnum>() 不好?
许多其他答案使用.Cast<SomeEnum>()。问题在于它使用了Array 类的非通用IEnumerable 实现。这应该涉及将每个值装箱到System.Object 框中,然后使用Cast<> 方法再次取消装箱所有这些值。幸运的是,.Cast<> 方法似乎在开始迭代集合之前检查了其IEnumerable 参数(this 参数)的运行时类型,所以它毕竟不是那么糟糕。原来.Cast<> 允许同一个数组实例通过。
如果您通过.ToArray() 或.ToList() 关注它,如:
Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList() // DON'T do this
您还有另一个问题:当您调用GetValues 时创建了一个新集合(数组),然后使用.ToList() 调用创建了一个新集合(List<>)。所以这是整个集合的一个(额外)冗余分配来保存值。
更新:自 .NET 5.0(从 2020 年起),以上信息已过时;终于有了一个泛型方法(泛型从 2005 年开始在 .NET Framework 2.0 中引入),所以现在您应该简单地使用:
Enum.GetValues<SomeEnum>()
其返回参数是强类型的(如SomeEnum[])。
【讨论】:
(SomeEnum[])Enum.GetValues(typeof(SomeEnum)) 也是IEnumerable 和IEnumerable<SomeEnum>,它也是IList 和IList<SomeEnum>。但是,如果您以后需要添加或删除条目,以便列表的长度发生变化,您可以复制到List<SomeEnum>,但这不是最常见的需要。
Enum.GetValue<T>()。
这是我喜欢的方式,使用 LINQ:
public class EnumModel
{
public int Value { get; set; }
public string Name { get; set; }
}
public enum MyEnum
{
Name1=1,
Name2=2,
Name3=3
}
public class Test
{
List<EnumModel> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => new EnumModel() { Value = (int)c, Name = c.ToString() }).ToList();
// A list of Names only, does away with the need of EnumModel
List<string> MyNames = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => c.ToString()).ToList();
// A list of Values only, does away with the need of EnumModel
List<int> myValues = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => (int)c).ToList();
// A dictionnary of <string,int>
Dictionary<string,int> myDic = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToDictionary(k => k.ToString(), v => (int)v);
}
希望对你有帮助
【讨论】:
((IEnumerable<EnumModel>)Enum.GetValues 应该是((IEnumerable<MyEnum>)Enum.GetValues
List <SomeEnum> theList = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();
【讨论】:
很简单的答案
这是我在我的一个应用程序中使用的属性
public List<string> OperationModes
{
get
{
return Enum.GetNames(typeof(SomeENUM)).ToList();
}
}
【讨论】:
我一直习惯于像这样获取enum 值的列表:
Array list = Enum.GetValues(typeof (SomeEnum));
【讨论】:
这里是为了有用...一些用于将值转换为列表的代码,它将枚举转换为文本的可读形式
public class KeyValuePair
{
public string Key { get; set; }
public string Name { get; set; }
public int Value { get; set; }
public static List<KeyValuePair> ListFrom<T>()
{
var array = (T[])(Enum.GetValues(typeof(T)).Cast<T>());
return array
.Select(a => new KeyValuePair
{
Key = a.ToString(),
Name = a.ToString().SplitCapitalizedWords(),
Value = Convert.ToInt32(a)
})
.OrderBy(kvp => kvp.Name)
.ToList();
}
}
.. 以及配套的 System.String 扩展方法:
/// <summary>
/// Split a string on each occurrence of a capital (assumed to be a word)
/// e.g. MyBigToe returns "My Big Toe"
/// </summary>
public static string SplitCapitalizedWords(this string source)
{
if (String.IsNullOrEmpty(source)) return String.Empty;
var newText = new StringBuilder(source.Length * 2);
newText.Append(source[0]);
for (int i = 1; i < source.Length; i++)
{
if (char.IsUpper(source[i]))
newText.Append(' ');
newText.Append(source[i]);
}
return newText.ToString();
}
【讨论】:
(T[])(Enum.GetValues(typeof(T)).Cast<T>()) 时,仔细查看括号,我们看到您实际上将Cast<T> 的返回值转换为T[]。这很令人困惑(也许它甚至会起作用)。跳过Cast<T> 电话。有关详细信息,请参阅我的新答案。
Language[] result = (Language[])Enum.GetValues(typeof(Language))
【讨论】:
public class NameValue
{
public string Name { get; set; }
public object Value { get; set; }
}
public class NameValue
{
public string Name { get; set; }
public object Value { get; set; }
}
public static List<NameValue> EnumToList<T>()
{
var array = (T[])(Enum.GetValues(typeof(T)).Cast<T>());
var array2 = Enum.GetNames(typeof(T)).ToArray<string>();
List<NameValue> lst = null;
for (int i = 0; i < array.Length; i++)
{
if (lst == null)
lst = new List<NameValue>();
string name = array2[i];
T value = array[i];
lst.Add(new NameValue { Name = name, Value = value });
}
return lst;
}
将枚举转换为列表更多可用信息here。
【讨论】:
T[] 的返回值转换为Cast<T> 会造成不必要的混乱。请参阅我最近的回答。
private List<SimpleLogType> GetLogType()
{
List<SimpleLogType> logList = new List<SimpleLogType>();
SimpleLogType internalLogType;
foreach (var logtype in Enum.GetValues(typeof(Log)))
{
internalLogType = new SimpleLogType();
internalLogType.Id = (int) (Log) Enum.Parse(typeof (Log), logtype.ToString(), true);
internalLogType.Name = (Log)Enum.Parse(typeof(Log), logtype.ToString(), true);
logList.Add(internalLogType);
}
return logList;
}
在顶部代码中,Log 是一个 Enum,SimpleLogType 是一个日志结构。
public enum Log
{
None = 0,
Info = 1,
Warning = 8,
Error = 3
}
【讨论】:
foreach 变量具有编译时类型object(写为var),但它确实是Log 值(运行时类型)。无需拨打ToString,然后拨打Enum.Parse。用这个来开始你的foreach:foreach (var logtype in (Log[])Enum.GetValues(typeof(Log))) { ... }
/// <summary>
/// Method return a read-only collection of the names of the constants in specified enum
/// </summary>
/// <returns></returns>
public static ReadOnlyCollection<string> GetNames()
{
return Enum.GetNames(typeof(T)).Cast<string>().ToList().AsReadOnly();
}
其中 T 是一种枚举类型; 添加这个:
using System.Collections.ObjectModel;
【讨论】:
如果您希望 Enum int 作为键和名称作为值,最好将数字存储到数据库并且它来自 Enum!
void Main()
{
ICollection<EnumValueDto> list = EnumValueDto.ConvertEnumToList<SearchDataType>();
foreach (var element in list)
{
Console.WriteLine(string.Format("Key: {0}; Value: {1}", element.Key, element.Value));
}
/* OUTPUT:
Key: 1; Value: Boolean
Key: 2; Value: DateTime
Key: 3; Value: Numeric
*/
}
public class EnumValueDto
{
public int Key { get; set; }
public string Value { get; set; }
public static ICollection<EnumValueDto> ConvertEnumToList<T>() where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new Exception("Type given T must be an Enum");
}
var result = Enum.GetValues(typeof(T))
.Cast<T>()
.Select(x => new EnumValueDto { Key = Convert.ToInt32(x),
Value = x.ToString(new CultureInfo("en")) })
.ToList()
.AsReadOnly();
return result;
}
}
public enum SearchDataType
{
Boolean = 1,
DateTime,
Numeric
}
【讨论】:
您可以使用以下通用方法:
public static List<T> GetItemsList<T>(this int enums) where T : struct, IConvertible
{
if (!typeof (T).IsEnum)
{
throw new Exception("Type given must be an Enum");
}
return (from int item in Enum.GetValues(typeof (T))
where (enums & item) == item
select (T) Enum.Parse(typeof (T), item.ToString(new CultureInfo("en")))).ToList();
}
【讨论】:
int,然后在int 上使用奇怪的文化调用ToString,然后将字符串解析回类型T?投反对票。