我有一个小方法,如下所示:
public void SetOptions<T>() where T : Enum
{
int i = 0;
foreach (T obj in Enum.GetValues(typeof(T)))
{
if (i == 0)
DefaultOption = new ListItem(obj.Description(), obj.ToString());
i++;
DropDownList.Items.Add(new ListItem(obj.Description(), obj.ToString()));
}
}
基本上,我从枚举中填充下拉列表。 Description()
实际上是枚举的扩展方法,因此T
绝对是enum
。
但是,我想像obj
那样将(int)obj
转换为它的索引,但我得到一个错误,说我无法将T转换为int。有没有办法做到这一点?
答案 0 :(得分:36)
试试这个,
public void SetOptions<T>()
{
Type genericType = typeof(T);
if (genericType.IsEnum)
{
foreach (T obj in Enum.GetValues(genericType))
{
Enum test = Enum.Parse(typeof(T), obj.ToString()) as Enum;
int x = Convert.ToInt32(test); // x is the integer value of enum
..........
..........
}
}
}
答案 1 :(得分:13)
您还可以先将值转换为object
,然后再转换为int
。
具有Enum
通用约束。
public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
=> (int)(object)value;
没有Enum
通用约束。
public static int EnumToInt<TValue>(this TValue value) where TValue : struct, IConvertible
{
if(!typeof(TValue).IsEnum)
{
throw new ArgumentException(nameof(value));
}
return (int)(object)value;
}
如果您的枚举继承自其他类型,例如从byte
继承,则强制转换为int将抛出InvalidCastException
。
您可以检查枚举的基本类型是否为整数。
public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
{
if (!typeof(int).IsAssignableFrom(Enum.GetUnderlyingType(typeof(TValue))))
throw new ArgumentException(nameof(TValue));
return (int)(object)value;
}
或者,如果您使用Convert.ToInt32
,它将使用int32的IConvertible
接口转换不兼容的类型。
public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
=> Convert.ToInt32(value);
请注意,将uint
转换为int
和有符号/无符号对可能会导致意外行为。 (装箱到IConvertible
,转换的效果不如装箱。)
我建议为每种枚举基类型创建一个方法,以确保返回正确的结果。
答案 2 :(得分:5)
这个正在使用任何基础类型
Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()))
什么时候适用?例如,当您想要将值添加到SqlCommand
时,会将枚举转换为0
,并且您必须将其明确地转换为匹配类型。但我们可以写下面的扩展名:
public static void AddEnum(this SqlParameterCollection parameters, string parameterName, Enum value)
{
parameters.AddWithValue(parameterName, Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType())));
}
这为我们做了一切。
答案 3 :(得分:3)
如果目标是.NET Core,则可以使用Unsafe.As<TFrom, TTo>
名称空间中的System.Runtime.CompilerServices
,如MSDN所述。这样做的好处是不需要装箱,这是这里其他答案中唯一的实际性能成本。
private static int EnumToInt<TEnum>(TEnum enumValue) where TEnum : Enum
{
return Unsafe.As<TEnum, int>(enumValue);
}
请注意,此方法与其他现有答案一样也存在安全问题:不能保证给定的枚举是兼容的int
类型,这很可能是未烘焙此功能的相同原因。如果在内部使用此方法,可以确保传递给它的任何枚举是兼容类型,那么这可能是最有效的方法。
Here是指向dotnet GitHub页面上某个问题的链接,该问题在此处提出,如果您想了解更多,一些开发人员就此方法进行了详细说明。
答案 4 :(得分:3)
这是我的C#7.3及更高版本的解决方案。与OP的问题不完全匹配,但对于从Google找到这个问题的人来说可能很有用。相对于其他答案的主要优势是它返回了ulong,这意味着任何允许的枚举类型都将适合其中。为此,我还制作了comparison的机器代码和其他一些答案。是的,我很无聊,并且想过早进行优化。
private static unsafe ulong EnumAsUInt64<T>(T item) where T : unmanaged, Enum
{
ulong x;
if (sizeof(T) == 1)
x = *(byte*)(&item);
else if (sizeof(T) == 2)
x = *(ushort*)(&item);
else if (sizeof(T) == 4)
x = *(uint*)(&item);
else if (sizeof(T) == 8)
x = *(ulong*)(&item);
else
throw new ArgumentException("Argument is not a usual enum type; it is not 1, 2, 4, or 8 bytes in length.");
return x;
}
答案 5 :(得分:2)
我很惊讶你的代码可以运行。 Enum.GetValues
返回一个整数数组 - 这是您要查找的值。而且,正如其他人所提到的,you can't constrain your generics to an enum。
相反,您应该将Description
方法称为常规静态方法,而不是扩展方法。
答案 6 :(得分:2)
你可以滥用 GetHashCode吗?
public enum MyEnum
{
Foo = 100,
Bar = 200,
Fizz = 0
}
static void Main(string[] args)
{
var i1 = MyEnum.Foo.GetHashCode(); // i1 = 100
var i2 = MyEnum.Bar.GetHashCode(); // i2 = 200
var i3 = MyEnum.Fizz.GetHashCode(); // i3 = 0
}
请注意:“GetHashCode()
按设计仅对一件事有用:将对象放入哈希表中。因此名称。” - E. Lippert
答案 7 :(得分:1)
派对有点晚了,但是使用Linq这可以优雅地完成:
public static void SetOptions<T>(this DropDownList dropDownList)
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Type must be an enum type.");
}
dropDownList.Items.AddRange(Enum
.GetValues(typeof(T))
.Cast<Enum>()
.Select(x => new ListItem(x.ToString(), Convert.ToInt32(x).ToString()))
.ToArray());
}
答案 8 :(得分:1)
这是一种更简单的方法。
由于Enum实现了IConvertible,我们可以使用ToInt32(..)。
int? value = (enumCandidate as IConvertible)?.ToInt32(CultureInfo.InvariantCulture.Numberformat);
或者,如果您喜欢通用枚举的通用方法:
public static int GetEnumValue<T>(T inputEnum) where T: struct, IConvertible
{
Type t = typeof(T);
if (!t.IsEnum)
{
throw new ArgumentException("Input type must be an enum.");
}
return inputEnum.ToInt32(CultureInfo.InvariantCulture.NumberFormat);
}
或者更一般:
public static int GetEnumValue(object enumInput)
{
Type t = enumInput.GetType();
if (!t.IsEnum)
{
throw new ArgumentException("Input type must be an enum.");
}
return ((IConvertible)inputEnum).ToInt32(CultureInfo.InvariantCulture.NumberFormat);
}
答案 9 :(得分:1)
只需将通用T强制转换为对象
T value;
int int_value = (int)(object)value;
就是这样。
答案 10 :(得分:0)
尝试以下操作:(假设TEnum的编号从0到n)
public void SetOptions<TEnum>() where TEnum : Enum
{
foreach (TEnum obj in Enum.GetValues(typeof(TEnum)))
{
var i = (int)(object)obj;
if (i == 0) DefaultOption = new ListItem(obj.Description(), obj.ToString());
DropDownList.Items.Add(new ListItem(obj.Description(), obj.ToString()));
}
}
答案 11 :(得分:0)
如果使用限制通用T为枚举
where T: Enum
然后您可以使用下面的单层纸
public static int GetIndexFromEnum<T>(T enumValue) where T : Enum {
int index = Convert.ToInt32(enumValue);
return index;
}
这似乎是最简单的解决方案,只要您可以确保T将成为枚举即可。
答案 12 :(得分:-3)
扩展Jan关于泛型和枚举值的答案:
void MyFunc<T>(T value)
{
Type t = typeof(T);
if(t.IsEnum)
{
int valueAsInt = value.GetHashCode(); // returns the integer value
}
}