Chciałbym stworzyć ogólną metodę konwersji dowolnego typu pochodnego System.Enum na odpowiadającą mu wartość całkowitą, bez rzutowania, a najlepiej bez analizowania ciągu.
Np. Chcę coś takiego:
// Trivial example, not actually what I'm doing.
class Converter
{
int ToInteger(System.Enum anEnum)
{
(int)anEnum;
}
}
Ale to nie działa. Resharper zgłasza, że nie można rzutować wyrażenia typu „System.Enum” na typ „int”.
Teraz wymyśliłem to rozwiązanie, ale wolałbym mieć coś wydajniejszego.
class Converter
{
int ToInteger(System.Enum anEnum)
{
return int.Parse(anEnum.ToString("d"));
}
}
Jakieś sugestie?
c#
enums
type-conversion
orj
źródło
źródło
Odpowiedzi:
Jeśli nie chcesz przesyłać,
mógłby załatwić sprawę.
Bezpośrednia obsada (via
(int)enumValue
) nie jest możliwa. Należy pamiętać, że będzie to także „niebezpieczne”, ponieważ enum mogą mieć różne typy bazowe (int
,long
,byte
...).Bardziej formalnie:
System.Enum
nie ma bezpośredniego związku dziedziczenia zInt32
(chociaż oba sąValueType
s), więc jawne rzutowanie nie może być poprawne w systemie typówźródło
Converter.ToInteger(MyEnum.MyEnumConstant);
nie poda tutaj żadnego błędu. Edytuj tę część.int
long
enum.System.Enum
jest klasą, więc jest typem referencyjnym. Wartości są prawdopodobnie w ramkach.Mam to do pracy, rzucając na obiekt, a następnie na int:
public static class EnumExtensions { public static int ToInt(this Enum enumValue) { return (int)((object)enumValue); } }
To jest brzydkie i prawdopodobnie nie jest to najlepszy sposób. Będę się tym bawić, aby zobaczyć, czy uda mi się wymyślić coś lepszego ....
EDYCJA: Właśnie miałem napisać, że Convert.ToInt32 (enumValue) również działa i zauważyłem, że MartinStettner mnie pokonał.
public static class EnumExtensions { public static int ToInt(this Enum enumValue) { return Convert.ToInt32(enumValue); } }
Test:
int x = DayOfWeek.Friday.ToInt(); Console.WriteLine(x); // results in 5 which is int value of Friday
EDYCJA 2: W komentarzach ktoś powiedział, że działa to tylko w C # 3.0. Właśnie przetestowałem to w VS2005 w ten sposób i zadziałało:
public static class Helpers { public static int ToInt(Enum enumValue) { return Convert.ToInt32(enumValue); } } static void Main(string[] args) { Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday)); }
źródło
Jeśli chcesz przekonwertować dowolne wyliczenie na jego typ bazowy (nie wszystkie wyliczenia są obsługiwane przez
int
), możesz użyć:return System.Convert.ChangeType( enumValue, Enum.GetUnderlyingType(enumValue.GetType()));
źródło
Convert.ChangeType
akceptujeobject
jako pierwszy argument i zwracaobject
.Dlaczego musisz na nowo wynaleźć koło za pomocą metody pomocniczej? Rzucanie
enum
wartości na jej typ bazowy jest całkowicie legalne .To mniej pisania, a moim zdaniem bardziej czytelne, w użyciu ...
int x = (int)DayOfWeek.Tuesday;
... zamiast czegoś w rodzaju ...
int y = Converter.ToInteger(DayOfWeek.Tuesday); // or int z = DayOfWeek.Tuesday.ToInteger();
źródło
Z mojej odpowiedzi tutaj :
Podano
e
jak w:Wtedy te działają:
int i = Convert.ToInt32(e); int i = (int)(object)e; int i = (int)Enum.Parse(e.GetType(), e.ToString()); int i = (int)Enum.ToObject(e.GetType(), e);
Ostatnie dwa są po prostu brzydkie. Pierwsza powinna być bardziej czytelna, choć druga jest znacznie szybsza. A może metoda rozszerzenia jest najlepsza, najlepsza z obu światów.
public static int GetIntValue(this Enum e) { return e.GetValue<int>(); } public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T> { return (T)(object)e; }
Teraz możesz zadzwonić:
e.GetValue<int>(); //or e.GetIntValue();
źródło
e
zmienna ma już opakowane wystąpienie rzeczywistego typu wartości, tj. wyliczenie. Kiedy piszeszEnum e = Question.Role;
, jest już zapakowane. Pytanie dotyczy konwersji pudełkowanego zSystem.Enum
powrotem do bazowego typu int (unboxing). Więc tutaj rozpakowywanie to tylko kwestia wydajności.(int)(object)e
jest bezpośrednim wywołaniem unbox; tak, powinno być szybsze niż inne podejścia. Zobacz toPrzesyłanie z a
System.Enum
do aint
działa dla mnie dobrze (jest również w MSDN ). Może to błąd Resharper.źródło
System.Enum
, a nieSystem.Enum
siebie.Ponieważ wyliczenia są ograniczone do bajtów, sbyte, short, ushort, int, uint, long i ulong, możemy poczynić pewne założenia.
Możemy uniknąć wyjątków podczas konwersji, używając największego dostępnego kontenera. Niestety, którego pojemnika należy użyć, nie jest jasne, ponieważ ulong wysadzi w przypadku liczb ujemnych, a long dla liczb z przedziału od long.MaxValue do ulong.MaxValue. Musimy przełączać się między tymi opcjami w oparciu o podstawowy typ.
Oczywiście nadal musisz zdecydować, co zrobić, gdy wynik nie mieści się w int. Myślę, że casting jest w porządku, ale wciąż są pewne problemy:
Oto moja sugestia, pozostawię to czytelnikowi, aby zdecydował, gdzie ujawnić tę funkcję; jako pomocnik lub rozszerzenie.
public int ToInt(Enum e) { unchecked { if (e.GetTypeCode() == TypeCode.UInt64) return (int)Convert.ToUInt64(e); else return (int)Convert.ToInt64(e); } }
źródło
Nie zapominaj, że sam typ Enum zawiera kilka statycznych funkcji pomocniczych. Jeśli wszystko, co chcesz zrobić, to przekonwertować wystąpienie wyliczenia na odpowiadający mu typ liczby całkowitej, rzutowanie jest prawdopodobnie najbardziej wydajnym sposobem.
Myślę, że ReSharper narzeka, ponieważ Enum nie jest wyliczeniem żadnego określonego typu, a same wyliczenia pochodzą ze skalarnego typu wartości, a nie Enum. Jeśli potrzebujesz adaptowalnego rzutowania w ogólny sposób, powiedziałbym, że może ci to dobrze odpowiadać (zwróć uwagę, że sam typ wyliczenia jest również zawarty w generycznym:
public static EnumHelpers { public static T Convert<T, E>(E enumValue) { return (T)enumValue; } }
Można to następnie wykorzystać w następujący sposób:
public enum StopLight: int { Red = 1, Yellow = 2, Green = 3 } // ... int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);
Nie mogę powiedzieć z całą pewnością, ale powyższy kod może być nawet obsługiwany przez wnioskowanie o typie C #, pozwalając na:
int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);
źródło
EnumHelpers.Convert<int, StopLight>(StopLight.Red);
zamiast(int)StopLight.Read;
? Również o tym mowaSystem.Enum
.