Como faço para converter enum genérico para int?

Eu tenho um pequeno método que se parece com isso:

public void SetOptions() 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())); } } 

Basicamente, eu preencho uma lista suspensa de um enum. Description() é na verdade um método de extensão para enums, então T é definitivamente um enum .

No entanto, eu quero converter obj assim como você faria qualquer enum para seu índice como este (int)obj , mas recebo um erro dizendo que não posso converter T para int. Há alguma maneira de fazer isso?

tente isso,

 public void SetOptions() { 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 .......... .......... } } } 

Você também pode converter seu valor para object primeiro e depois para int .

C # 7.3 e acima

Com a restrição genérica Enum .

 public static int EnumToInt(this TValue value) where TValue : Enum => (int)(object)value; 

Abaixo de C # 7.3

Sem a restrição genérica Enum .

 public static int EnumToInt(this TValue value) where TValue : struct, IConvertible { if(!typeof(TValue).IsEnum) { throw new ArgumentException(nameof(value)); } return (int)(object)value; } 

Se seu enum herdar de outros tipos, por exemplo, de byte o cast para int lançará um InvalidCastException .

Você pode verificar se o tipo base do enum é um inteiro.

 public static int EnumToInt(this TValue value) where TValue : Enum { if (!typeof(int).IsAssignableFrom(Enum.GetUnderlyingType(typeof(TValue)))) throw new ArgumentException(nameof(TValue)); return (int)(object)value; } 

Ou você, se usar Convert.ToInt32 , usará a interface IConvertible do int32 para converter os tipos incoerentes.

 public static int EnumToInt(this TValue value) where TValue : Enum => Convert.ToInt32(value); 

Apenas esteja ciente de que a conversão de uint para int e outros suff pode causar behaivoir não intencional. (E o boxe para o IConvertible e a conversão têm menos performance que apenas o unboxing.)


Eu recomendo criar um método para cada tipo de base de enum para garantir que o resultado correto seja retornado.

Este está trabalhando com qualquer tipo subjacente

 Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType())) 

Quando é aplicável? Por exemplo, quando você deseja adicionar um valor ao SqlCommand , que converte enums para 0 e você deve explicitamente converter para o tipo correspondente. Mas podemos escrever a seguinte extensão:

 public static void AddEnum(this SqlParameterCollection parameters, string parameterName, Enum value) { parameters.AddWithValue(parameterName, Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()))); } 

Que está fazendo tudo por nós.

Estou surpreso que seu código funcione. Enum.GetValues retorna uma matriz de inteiros – que são os valores que você está procurando. E, como outros já mencionaram, você não pode restringir seus genéricos a um enum .

Em vez disso, você provavelmente deve chamar seu método de Description como um método estático regular e não um método de extensão.

Você pode abusar do GetHashCode para isso?

 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 } 

Por favor note: ” GetHashCode() é por design útil para apenas uma coisa: colocar um object em uma tabela de hash. Daí o nome.” – E. Lippert

Um pouco atrasado para a festa, mas usando o Linq isso pode ser feito elegantemente:

 public static void SetOptions(this DropDownList dropDownList) { if (!typeof(T).IsEnum) { throw new ArgumentException("Type must be an enum type."); } dropDownList.Items.AddRange(Enum .GetValues(typeof(T)) .Cast() .Select(x => new ListItem(x.ToString(), Convert.ToInt32(x).ToString())) .ToArray()); } 

Aqui está uma maneira mais simples.

Como o Enum implementa o IConvertible, podemos usar o ToInt32 (..).

 int? value = (enumCandidate as IConvertible)?.ToInt32(CultureInfo.InvariantCulture.Numberformat); 

Ou se você quiser um método de uso geral para enums genéricos:

 public static int GetEnumValue(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); } 

Ou ainda mais geral:

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

Para expandir a resposta de Jan sobre os valores genéricos e enum:

 void MyFunc(T value) { Type t = typeof(T); if(t.IsEnum) { int valueAsInt = value.GetHashCode(); // returns the integer value } }