Jak rzucić int na enum?


Odpowiedzi:


3790

Z ciągu:

YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);

// The foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
{
    throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")
}

Od int:

YourEnum foo = (YourEnum)yourInt;

Aktualizacja:

Z numeru możesz także

YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);

31
@FlySwat, co jeśli YourEnumjest dynamiczny i będzie znany tylko w środowisku wykonawczym, a to, czego chcę, to konwersja Enum?
Shimmy Weitzhandler

226
Pamiętaj, że Enum.Parse NIE będzie działać, jeśli twój kod jest zaciemniony. W czasie wykonywania po zaciemnieniu ciąg jest porównywany z nazwami wyliczeń, aw tym momencie nazwy wyliczeń nie są takie, jak można by się spodziewać. W rezultacie Twoja analiza zakończy się niepowodzeniem tam, gdzie wcześniej się powiodła.
jropella

158
UWAGA: Jeśli użyjesz powyższej składni „z ciągu” i przekażesz niepoprawny ciąg, który jest liczbą (np. „2342342” - zakładając, że nie jest to wartość twojego wyliczenia), to na to pozwoli bez zgłaszania błędu! Twoje wyliczenie będzie miało tę wartość (2342342), nawet jeśli nie jest to prawidłowy wybór w samym wyliczeniu.
JoeCool,

132
Myślę, że ta odpowiedź jest już trochę przestarzała. W przypadku łańcucha znaków powinieneś naprawdę używać var result = Enum.TryParse(yourString, out yourEnum)obecnie (i sprawdzać wynik, aby ustalić, czy konwersja nie powiodła się).
Justin T Conroy

20
Można również Enum.Parserozróżniać małe i wielkie litery, dodając truewartość parametru do wywołania:YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Erik Schierboom

900

Po prostu rzuć to:

MyEnum e = (MyEnum)3;

Możesz sprawdzić, czy jest w zasięgu za pomocą Enum.IsDefined :

if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }

218
Uważaj, że nie możesz użyć Enum.IsDefined, jeśli używasz atrybutu Flagi, a wartość jest kombinacją flag, na przykład: Keys.L | Keys.Control
dtroy

15
Jeśli chodzi o Enum.IsDefined, należy pamiętać, że może to być niebezpieczne: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
Adri

3
Wolę tę definicję: „Zwraca wskazanie, czy stała o określonej wartości istnieje w określonym wyliczeniu” z MSDN
Pap

3
... Ponieważ twoja definicja może wprowadzać w błąd, ponieważ mówisz: „... sprawdź, czy jest w zasięgu ...”, co oznacza, że ​​mieści się w zakresie liczb z limitami początkowymi i końcowymi ...
Pap

3
@ mac9416 Próbowałem podać zwięzły przykład na gist.github.com/alowdon/f7354cda97bac70b44e1c04bc0991bcc - w zasadzie za pomocą IsDefinedsprawdzania wartości wejściowych narażasz się na ryzyko, że ludzie dodadzą nowe wartości wyliczenia później, co przejdzie IsDefinedkontrolę (od czasu nowej wartość istnieje w nowym kodzie), ale może nie działać z oryginalnym kodem, który napisałeś. Dlatego bezpieczniej jest jawnie określić wartości wyliczeniowe, które twój kod jest w stanie obsłużyć.
adrian

238

Alternatywnie użyj metody rozszerzenia zamiast jednowarstwowej:

public static T ToEnum<T>(this string enumString)
{
    return (T) Enum.Parse(typeof (T), enumString);
}

Stosowanie:

Color colorEnum = "Red".ToEnum<Color>();

LUB

string color = "Red";
var colorEnum = color.ToEnum<Color>();

7
W przypadku przetwarzania danych wprowadzonych przez użytkownika prawdopodobnie dobrym pomysłem jest wywołanie przeciążenia Enum.Parse, który pozwala określić, że porównanie NIE będzie rozróżniało wielkości liter (tj. Użytkownik wpisujący „czerwony” (małe litery) spowodowałby awarię powyższego kodu bez tej zmiany .)
BrainSlugs83

9
Przydatne, ale pytanie dotyczy w szczególności ints.
BJury

2
działa to również, jeśli ciąg znaków jest liczbą całkowitą, np. „2”
TruthOf42,

2
Spowoduje to zgłoszenie wyjątku, jeśli enumString ma wartość NULL (miał podobny problem wczoraj). Rozważ użycie TryParse zamiast Parse. TryParse sprawdzi również, czy T jest typem Enum
Justin

Ten rodzaj metody rozszerzenia System.Stringwydaje się jak zanieczyszczenie przestrzeni nazw
Pan Anderson

160

Myślę, że aby uzyskać pełną odpowiedź, ludzie muszą wiedzieć, jak wyliczenia działają wewnętrznie w .NET.

Jak działają rzeczy

Wyliczenie w .NET to struktura, która odwzorowuje zestaw wartości (pól) na typ podstawowy (domyślnie jest int). Możesz jednak wybrać typ całki, na który odwzorowuje twój enum:

public enum Foo : short

W tym przypadku wyliczenie jest odwzorowane na shorttyp danych, co oznacza, że ​​zostanie zapisane w pamięci jako krótkie i będzie zachowywać się jak krótkie po rzutowaniu i użyciu.

Jeśli spojrzysz na to z punktu widzenia IL, wyliczenie (normalne, int) wygląda następująco:

.class public auto ansi serializable sealed BarFlag extends System.Enum
{
    .custom instance void System.FlagsAttribute::.ctor()
    .custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }

    .field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
    .field public static literal valuetype BarFlag Foo1 = int32(1)
    .field public static literal valuetype BarFlag Foo2 = int32(0x2000)

    // and so on for all flags or enum values

    .field public specialname rtspecialname int32 value__
}

Należy zwrócić uwagę na to, że value__są przechowywane oddzielnie od wartości wyliczeniowych. W przypadku Foopowyższego wyliczenia typem value__jest int16. Zasadniczo oznacza to, że możesz przechowywać, co chcesz, w wyliczeniu, o ile typy są zgodne .

W tym miejscu chciałbym wskazać, że System.Enumjest to typ wartości, co w zasadzie oznacza, że BarFlagzajmie 4 bajty w pamięci i Foozajmie 2 - np. Rozmiar typu bazowego (jest to w rzeczywistości bardziej skomplikowane, ale Hej...).

Odpowiedź

Jeśli więc masz liczbę całkowitą, którą chcesz zmapować do wyliczenia, środowisko wykonawcze musi tylko zrobić 2 rzeczy: skopiować 4 bajty i nazwać to czymś innym (nazwa wyliczenia). Kopiowanie jest niejawne, ponieważ dane są przechowywane jako typ wartości - oznacza to po prostu, że jeśli używasz niezarządzanego kodu, możesz po prostu zamieniać wyliczenia i liczby całkowite bez kopiowania danych.

Dla bezpieczeństwa uważam, że najlepszą praktyką jest wiedzieć, że typy bazowe są takie same lub domyślnie konwertowalne oraz aby zapewnić istnienie wartości wyliczeniowych (domyślnie nie są sprawdzane!).

Aby zobaczyć, jak to działa, wypróbuj następujący kod:

public enum MyEnum : int
{
    Foo = 1,
    Bar = 2,
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)5;
    var e2 = (MyEnum)6;

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

Pamiętaj, że rzutowanie e2również działa! Z powyższego punktu widzenia kompilatora ma to sens: value__pole jest po prostu wypełnione albo 5 albo 6, a kiedy Console.WriteLinewywołania ToString(), nazwa e1zostaje rozwiązana, a nazwa e2nie.

Jeśli nie jest to zamierzone, użyj, Enum.IsDefined(typeof(MyEnum), 6)aby sprawdzić, czy wartość rzutujesz mapy do zdefiniowanego wyliczenia.

Zauważ też, że wyrażam się jasno o podstawowym typie wyliczenia, nawet jeśli kompilator faktycznie to sprawdza. Robię to, aby upewnić się, że nie spotka mnie żadna niespodzianka. Aby zobaczyć te niespodzianki w akcji, możesz użyć następującego kodu (faktycznie widziałem, że tak się często dzieje w kodzie bazy danych):

public enum MyEnum : short
{
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)32769; // will not compile, out of bounds for a short

    object o = 5;
    var e2 = (MyEnum)o;     // will throw at runtime, because o is of type int

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

7
Zdaję sobie sprawę, że to stary post, ale jak zdobyć ten poziom wiedzy w języku c #? Czy wynika to z przeczytania specyfikacji C #?
Rolan,

20
@Rolan Czasami chciałbym, żeby więcej osób o to pytało. :-) Szczerze mówiąc, tak naprawdę nie wiem; Staram się zrozumieć, jak działają rzeczy, i uzyskiwać informacje, gdzie tylko mogę. Przeczytałem standard C #, ale regularnie dekompiluję kod za pomocą Reflectora (często nawet patrzę na kod asemblera x86) i robię mnóstwo małych eksperymentów. Również znajomość innych języków pomaga w tym przypadku; Zajmuję się CS-em od około 30 lat iw pewnym momencie pewne rzeczy stają się „logiczne” - np. wyliczenie powinno integrować typy, ponieważ w przeciwnym razie interop przerwie (lub twoja wydajność spadnie do dna).
atlaste

9
Uważam, że kluczem do prawidłowego wykonania inżynierii oprogramowania jest wiedza, jak to działa. Dla mnie oznacza to, że jeśli napiszesz fragment kodu, wiesz, jak z grubsza to się przekłada na np. operacje procesora i pobieranie / zapisywanie w pamięci. Jeśli zapytasz, jak dostać się do tego poziomu, sugeruję zbudowanie mnóstwa małych przypadków testowych, czyniąc je trudniejszymi w miarę upływu czasu, spróbuj przewidzieć wynik za każdym razem, a następnie przetestuj je później (w tym dekompilację itp.). Po ustaleniu wszystkich szczegółów i wszystkich cech, możesz sprawdzić, czy masz rację w (nudnym) standardzie. Takie byłoby przynajmniej moje podejście.
atlaste

1
Fantastyczna odpowiedź, dzięki! W ostatnim przykładzie kodu zgłasza wyjątek w czasie wykonywania, ponieważ o jest obiektem. Możesz rzutować zmienną int na wartość krótką, o ile mieści się ona w krótkim zakresie.
gravidThoughts

@gravidThoughts Thanks. W rzeczywistości jest to operacja rozpakowywania, więc nie spowoduje żadnych niejawnych konwersji, takich jak te, które opisujesz. Przesyłanie jest czasem mylące w języku C #, jeśli nie znasz szczegółów ... W każdym razie, ponieważ int! = short, Wyrzuci (rozpakowanie nie powiedzie się). Jeśli to zrobisz object o = (short)5;, będzie działać, ponieważ wtedy typy będą pasować. Nie chodzi o zakres, ale o typ.
atlaste,


64

Korzystam z tego fragmentu kodu, aby rzucić int do mojego wyliczenia:

if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }

Uważam to za najlepsze rozwiązanie.


1
to jest dobre. Byłem zaskoczony, że nie ma wyjątku podczas rzutowania niepoprawnej wartości na wyliczenie int-backed.
orion elenzil

To tak naprawdę nie różni się od najlepiej ocenianej odpowiedzi. Ta odpowiedź omawia także użycie Enum.IsDefined po rzutowaniu ciągu na typ Enum. Nawet jeśli struna została rzucona bezbłędnie, Enum.IsDefined nadal ją złapie
Don Cheadle

53

Poniżej znajduje się niezła klasa użyteczności dla Enums

public static class EnumHelper
{
    public static int[] ToIntArray<T>(T[] value)
    {
        int[] result = new int[value.Length];
        for (int i = 0; i < value.Length; i++)
            result[i] = Convert.ToInt32(value[i]);
        return result;
    }

    public static T[] FromIntArray<T>(int[] value) 
    {
        T[] result = new T[value.Length];
        for (int i = 0; i < value.Length; i++)
            result[i] = (T)Enum.ToObject(typeof(T),value[i]);
        return result;
    }


    internal static T Parse<T>(string value, T defaultValue)
    {
        if (Enum.IsDefined(typeof(T), value))
            return (T) Enum.Parse(typeof (T), value);

        int num;
        if(int.TryParse(value,out num))
        {
            if (Enum.IsDefined(typeof(T), num))
                return (T)Enum.ToObject(typeof(T), num);
        }

        return defaultValue;
    }
}

47

W przypadku wartości liczbowych jest to bezpieczniejsze, ponieważ zwróci obiekt bez względu na wszystko:

public static class EnumEx
{
    static public bool TryConvert<T>(int value, out T result)
    {
        result = default(T);
        bool success = Enum.IsDefined(typeof(T), value);
        if (success)
        {
            result = (T)Enum.ToObject(typeof(T), value);
        }
        return success;
    }
}

Nie działa na wyliczanie flag
Seyed Morteza Mousavi


35

Jeśli masz liczbę całkowitą, która działa jak maska ​​bitowa i może reprezentować jedną lub więcej wartości w wyliczeniu [Flagi], możesz użyć tego kodu, aby przeanalizować poszczególne wartości flagi na liście:

for (var flagIterator = 0; flagIterator < 32; flagIterator++)
{
    // Determine the bit value (1,2,4,...,Int32.MinValue)
    int bitValue = 1 << flagIterator;

    // Check to see if the current flag exists in the bit mask
    if ((intValue & bitValue) != 0)
    {
        // If the current flag exists in the enumeration, then we can add that value to the list
        // if the enumeration has that flag defined
        if (Enum.IsDefined(typeof(MyEnum), bitValue))
            Console.WriteLine((MyEnum)bitValue);
    }
}

Zauważ, że zakłada to, że podstawowym typem enumjest 32-bitowa liczba całkowita ze znakiem. Gdyby był to inny typ liczbowy, musiałbyś zmienić kod 32, aby odzwierciedlić bity tego typu (lub programowo wyprowadzić go za pomocą Enum.GetUnderlyingType())


1
Czy ta pętla nigdy się nie kończy? flagIterator = 0x00000001, flagIterator = 0x00000002, flagIterator = 0x00000004, ..., flagIterator = 0x40000000, flagIterator = 0x80000000, flagIterator = 0x00000000. Innymi słowy, wartość zawsze będzie mniejsza niż 0x80000000, ponieważ przepełnia się do zera po przypadku, gdy bit D31 = 1. Następnie pozostaje 0 na zawsze, ponieważ przesunięcie w lewo wartości 0 daje 0
Christian Gingras

Świetny połów @ christiangingras, dziękuję! Zmodyfikowałem odpowiedź, aby uwzględnić to i powinno to wziąć pod uwagę, kiedy ustawiony jest najwyższy bit (tj. 0x80000000 / Int32.MinValue)
Evan M

27

Czasami masz obiekt tego MyEnumtypu. Lubić

var MyEnumType = typeof(MyEnumType);

Następnie:

Enum.ToObject(typeof(MyEnum), 3)

26

Jest to metoda bezpiecznej konwersji z uwzględnieniem wyliczania flag:

public static bool TryConvertToEnum<T>(this int instance, out T result)
  where T: Enum
{
  var enumType = typeof (T);
  var success = Enum.IsDefined(enumType, instance);
  if (success)
  {
    result = (T)Enum.ToObject(enumType, instance);
  }
  else
  {
    result = default(T);
  }
  return success;
}

3
Można to teraz ulepszyć za pomocą C # 7.3, ograniczając do Enumzamiast struct, co oznacza, że ​​nie musimy polegać na kontroli środowiska wykonawczego!
Scott,

20

wprowadź opis zdjęcia tutaj

Aby przekonwertować ciąg znaków na ENUM lub int na stałą ENUM, musimy użyć funkcji Enum.Parse. Oto film z youtube https://www.youtube.com/watch?v=4nhx4VwdRDk, który faktycznie pokazuje ciąg znaków i to samo dotyczy int.

Kod wygląda tak, jak pokazano poniżej, gdzie „czerwony” to ciąg znaków, a „MyColors” to kolor ENUM, który ma stałe kolorów.

MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");

20

Nieco uciekam od pierwotnego pytania, ale znalazłem odpowiedź na pytanie Przepełnienie stosu Uzyskaj wartość int z enum przydaje się. Utwórz klasę statyczną o public const intwłaściwościach, która pozwoli ci łatwo zebrać razem kilka powiązanych intstałych, a następnie nie musisz ich rzutować intpodczas ich używania.

public static class Question
{
    public static readonly int Role = 2;
    public static readonly int ProjectFunding = 3;
    public static readonly int TotalEmployee = 4;
    public static readonly int NumberOfServers = 5;
    public static readonly int TopBusinessConcern = 6;
}

Oczywiście niektóre funkcje typu wyliczania zostaną utracone, ale do przechowywania szeregu stałych identyfikatora bazy danych wydaje się to dość uporządkowane rozwiązanie.


5
wyliczenia zastąpiły użycie stałych całkowitych takich jak ten, ponieważ zapewniają większe bezpieczeństwo typu
Paul Richards

1
Paul, jest to metoda zbierania razem powiązanych stałych int (np. Stałych identyfikatora bazy danych), dzięki czemu można ich używać bezpośrednio, bez konieczności rzutowania ich na int za każdym razem, gdy są używane. Ich typ to liczba całkowita, nie na przykład DatabaseIdsEnum.
Ted

1
Znalazłem przynajmniej jedną sytuację, w której bezpieczeństwo typu wyliczeniowego można przypadkowo ominąć.
Thierry

Ale wyliczenia również upewniają się, że wszystkie wartości są unikalne, czegoś brakuje również w tym podejściu
derHugo,

15

To analizuje liczby całkowite lub ciągi do docelowego wyliczenia z częściowym dopasowaniem w dot.NET 4.0 przy użyciu ogólnych, takich jak w klasie użyteczności Tawani powyżej. Używam go do konwersji zmiennych przełączników wiersza polecenia, które mogą być niekompletne. Ponieważ wyliczenie nie może mieć wartości null, należy logicznie podać wartość domyślną. Można to nazwać tak:

var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);

Oto kod:

using System;

public class EnumParser<T> where T : struct
{
    public static T Parse(int toParse, T defaultVal)
    {
        return Parse(toParse + "", defaultVal);
    }
    public static T Parse(string toParse, T defaultVal) 
    {
        T enumVal = defaultVal;
        if (defaultVal is Enum && !String.IsNullOrEmpty(toParse))
        {
            int index;
            if (int.TryParse(toParse, out index))
            {
                Enum.TryParse(index + "", out enumVal);
            }
            else
            {
                if (!Enum.TryParse<T>(toParse + "", true, out enumVal))
                {
                    MatchPartialName(toParse, ref enumVal);
                }
            }
        }
        return enumVal;
    }

    public static void MatchPartialName(string toParse, ref T enumVal)
    {
        foreach (string member in enumVal.GetType().GetEnumNames())
        {
            if (member.ToLower().Contains(toParse.ToLower()))
            {
                if (Enum.TryParse<T>(member + "", out enumVal))
                {
                    break;
                }
            }
        }
    }
}

FYI: Pytanie dotyczyło liczb całkowitych, o których nikt nie wspomniał, które również zostaną jawnie przekonwertowane w Enum.TryParse ()


13

Z ciągu: (Enum.Parse jest nieaktualny, użyj Enum.TryParse)

enum Importance
{}

Importance importance;

if (Enum.TryParse(value, out importance))
{
}

4
Pytanie dotyczy w szczególności liczb całkowitych.
BJury

4
Czy Yu zredaguje twoją odpowiedź, aby wszyscy wiedzieli, że Enum.TryParse będzie działać na ciągu wartości lub nazwy wyliczenia (nie mogłem się oprzeć)
JeremyWeir

1
Jeremy, Weir nad tym pracuje (nie mógł się też oprzeć).
huysentruitw

11

Poniżej znajduje się nieco lepsza metoda rozszerzenia

public static string ToEnumString<TEnum>(this int enumValue)
        {
            var enumString = enumValue.ToString();
            if (Enum.IsDefined(typeof(TEnum), enumValue))
            {
                enumString = ((TEnum) Enum.ToObject(typeof (TEnum), enumValue)).ToString();
            }
            return enumString;
        }

10

W moim przypadku musiałem zwrócić wyliczenie z usługi WCF. Potrzebowałem także przyjaznej nazwy, nie tylko enum.ToString ().

Oto moja klasa WCF.

[DataContract]
public class EnumMember
{
    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public int Value { get; set; }

    public static List<EnumMember> ConvertToList<T>()
    {
        Type type = typeof(T);

        if (!type.IsEnum)
        {
            throw new ArgumentException("T must be of type enumeration.");
        }

        var members = new List<EnumMember>();

        foreach (string item in System.Enum.GetNames(type))
        {
            var enumType = System.Enum.Parse(type, item);

            members.Add(
                new EnumMember() { Description = enumType.GetDescriptionValue(), Value = ((IConvertible)enumType).ToInt32(null) });
        }

        return members;
    }
}

Oto metoda Extension, która pobiera Opis z Enum.

    public static string GetDescriptionValue<T>(this T source)
    {
        FieldInfo fileInfo = source.GetType().GetField(source.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fileInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);            

        if (attributes != null && attributes.Length > 0)
        {
            return attributes[0].Description;
        }
        else
        {
            return source.ToString();
        }
    }

Realizacja:

return EnumMember.ConvertToList<YourType>();

9

Nie wiem już, skąd biorę część tego rozszerzenia enum, ale pochodzi ono z przepełnienia stosu. Przepraszam za to! Ale wziąłem ten i zmodyfikowałem dla wyliczeń za pomocą Flags. W przypadku wyliczeń z flagami zrobiłem to:

  public static class Enum<T> where T : struct
  {
     private static readonly IEnumerable<T> All = Enum.GetValues(typeof (T)).Cast<T>();
     private static readonly Dictionary<int, T> Values = All.ToDictionary(k => Convert.ToInt32(k));

     public static T? CastOrNull(int value)
     {
        T foundValue;
        if (Values.TryGetValue(value, out foundValue))
        {
           return foundValue;
        }

        // For enums with Flags-Attribut.
        try
        {
           bool isFlag = typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
           if (isFlag)
           {
              int existingIntValue = 0;

              foreach (T t in Enum.GetValues(typeof(T)))
              {
                 if ((value & Convert.ToInt32(t)) > 0)
                 {
                    existingIntValue |= Convert.ToInt32(t);
                 }
              }
              if (existingIntValue == 0)
              {
                 return null;
              }

              return (T)(Enum.Parse(typeof(T), existingIntValue.ToString(), true));
           }
        }
        catch (Exception)
        {
           return null;
        }
        return null;
     }
  }

Przykład:

[Flags]
public enum PetType
{
  None = 0, Dog = 1, Cat = 2, Fish = 4, Bird = 8, Reptile = 16, Other = 32
};

integer values 
1=Dog;
13= Dog | Fish | Bird;
96= Other;
128= Null;

9

Powinieneś wbudować relaksację dopasowaną do typu, aby być bardziej niezawodnym.

public static T ToEnum<T>(dynamic value)
{
    if (value == null)
    {
        // default value of an enum is the object that corresponds to
        // the default value of its underlying type
        // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table
        value = Activator.CreateInstance(Enum.GetUnderlyingType(typeof(T)));
    }
    else if (value is string name)
    {
        return (T)Enum.Parse(typeof(T), name);
    }

    return (T)Enum.ToObject(typeof(T),
             Convert.ChangeType(value, Enum.GetUnderlyingType(typeof(T))));
}

Przypadek testowy

[Flags]
public enum A : uint
{
    None  = 0, 
    X     = 1 < 0,
    Y     = 1 < 1
}

static void Main(string[] args)
{
    var value = EnumHelper.ToEnum<A>(7m);
    var x = value.HasFlag(A.X); // true
    var y = value.HasFlag(A.Y); // true

    var value2 = EnumHelper.ToEnum<A>("X");

    var value3 = EnumHelper.ToEnum<A>(null);

    Console.ReadKey();
}

To miła odpowiedź. Szkoda, że ​​w tej chwili jest tak daleko od strony!
MikeBeaton

8

Różne sposoby przesyłania do iz Enum

enum orientation : byte
{
 north = 1,
 south = 2,
 east = 3,
 west = 4
}

class Program
{
  static void Main(string[] args)
  {
    orientation myDirection = orientation.north;
    Console.WriteLine(“myDirection = {0}”, myDirection); //output myDirection =north
    Console.WriteLine((byte)myDirection); //output 1

    string strDir = Convert.ToString(myDirection);
        Console.WriteLine(strDir); //output north

    string myString = north”; //to convert string to Enum
    myDirection = (orientation)Enum.Parse(typeof(orientation),myString);


 }
}

8

Może pomóc ci przekonwertować dowolne dane wejściowe na żądane przez użytkownika wyliczenie . Załóżmy, że masz wyliczenie jak poniżej, które domyślnie int . Dodaj wartość domyślną na początku swojego wyliczenia. Który jest używany w pomocnikach medthod, gdy nie znaleziono dopasowania z wartością wejściową.

public enum FriendType  
{
    Default,
    Audio,
    Video,
    Image
}

public static class EnumHelper<T>
{
    public static T ConvertToEnum(dynamic value)
    {
        var result = default(T);
        var tempType = 0;

        //see Note below
        if (value != null &&
            int.TryParse(value.ToString(), out  tempType) && 
            Enum.IsDefined(typeof(T), tempType))
        {
            result = (T)Enum.ToObject(typeof(T), tempType); 
        }
        return result;
    }
}

NB: Tutaj próbuję parsować wartość na int, ponieważ enum jest domyślnie int Jeśli zdefiniujesz enum jak ten, który jest typem bajtu .

public enum MediaType : byte
{
    Default,
    Audio,
    Video,
    Image
} 

Musisz zmienić parsowanie w metodzie pomocniczej z

int.TryParse(value.ToString(), out  tempType)

do

byte.TryParse(value.ToString(), out tempType)

Sprawdzam moją metodę pod kątem następujących danych wejściowych

EnumHelper<FriendType>.ConvertToEnum(null);
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("-1");
EnumHelper<FriendType>.ConvertToEnum("6");
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("2");
EnumHelper<FriendType>.ConvertToEnum(-1);
EnumHelper<FriendType>.ConvertToEnum(0);
EnumHelper<FriendType>.ConvertToEnum(1);
EnumHelper<FriendType>.ConvertToEnum(9);

przepraszam za mój angielski


8

Oto metoda rozszerzenia, która przesyła Int32do Enum.

Uwzględnia flagi bitowe, nawet jeśli wartość jest wyższa niż maksymalna możliwa. Na przykład, jeśli masz wyliczenie z możliwościami 1 , 2 i 4 , ale int wynosi 9 , rozumie to jako 1 przy braku 8 . Umożliwia to aktualizację danych przed aktualizacją kodu.

   public static TEnum ToEnum<TEnum>(this int val) where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        if (!typeof(TEnum).IsEnum)
        {
            return default(TEnum);
        }

        if (Enum.IsDefined(typeof(TEnum), val))
        {//if a straightforward single value, return that
            return (TEnum)Enum.ToObject(typeof(TEnum), val);
        }

        var candidates = Enum
            .GetValues(typeof(TEnum))
            .Cast<int>()
            .ToList();

        var isBitwise = candidates
            .Select((n, i) => {
                if (i < 2) return n == 0 || n == 1;
                return n / 2 == candidates[i - 1];
            })
            .All(y => y);

        var maxPossible = candidates.Sum();

        if (
            Enum.TryParse(val.ToString(), out TEnum asEnum)
            && (val <= maxPossible || !isBitwise)
        ){//if it can be parsed as a bitwise enum with multiple flags,
          //or is not bitwise, return the result of TryParse
            return asEnum;
        }

        //If the value is higher than all possible combinations,
        //remove the high imaginary values not accounted for in the enum
        var excess = Enumerable
            .Range(0, 32)
            .Select(n => (int)Math.Pow(2, n))
            .Where(n => n <= val && n > 0 && !candidates.Contains(n))
            .Sum();

        return Enum.TryParse((val - excess).ToString(), out asEnum) ? asEnum : default(TEnum);
    }

6

prosty i przejrzysty sposób na rzutowanie int na wyliczenie w c #:

 public class Program
    {
        public enum Color : int
        {
            Blue = 0,
            Black = 1,
            Green = 2,
            Gray = 3,
            Yellow =4
        }

        public static void Main(string[] args)
        {
            //from string
            Console.WriteLine((Color) Enum.Parse(typeof(Color), "Green"));

            //from int
            Console.WriteLine((Color)2);

            //From number you can also
            Console.WriteLine((Color)Enum.ToObject(typeof(Color) ,2));
        }
    }

6

Wystarczy użyć jawnej konwersji Cast int na enum lub enum na int

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine((int)Number.three); //Output=3

        Console.WriteLine((Number)3);// Outout three
        Console.Read();
    }

    public enum Number
    {
        Zero = 0,
        One = 1,
        Two = 2,
        three = 3
    }
}

4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace SamplePrograme
{
    public class Program
    {
        public enum Suit : int
        {
            Spades = 0,
            Hearts = 1,
            Clubs = 2,
            Diamonds = 3
        }

        public static void Main(string[] args)
        {
            //from string
            Console.WriteLine((Suit) Enum.Parse(typeof(Suit), "Clubs"));

            //from int
            Console.WriteLine((Suit)1);

            //From number you can also
            Console.WriteLine((Suit)Enum.ToObject(typeof(Suit) ,1));
        }
    }
}

3

Po prostu lubisz poniżej:

int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;

Aby upewnić się, że rzucisz tylko prawidłowe wartości i że możesz wrzucić wyjątek:

int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
    TargetEnum target = (TargetEnum)intToCast ;
}
else
{
   // Throw your exception.
}

Pamiętaj, że korzystanie z IsDefined jest kosztowne, a nawet więcej niż tylko rzutowanie, więc decyzja o jego użyciu zależy od implementacji.


3

Możesz użyć metody rozszerzenia.

public static class Extensions
{

    public static T ToEnum<T>(this string data) where T : struct
    {
        if (!Enum.TryParse(data, true, out T enumVariable))
        {
            if (Enum.IsDefined(typeof(T), enumVariable))
            {
                return enumVariable;
            }
        }

        return default;
    }

    public static T ToEnum<T>(this int data) where T : struct
    {
        return (T)Enum.ToObject(typeof(T), data);
    }
}

użyj jak poniżej kodu

wyliczenie:

public enum DaysOfWeeks
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
    Sunday = 7,
}

Stosowanie :

 string Monday = "Mon";
 int Wednesday = 3;
 var Mon = Monday.ToEnum<DaysOfWeeks>();
 var Wed = Wednesday.ToEnum<DaysOfWeeks>();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.