Vraag Cast int op te nemen in C #


Hoe kan een int worden geworpen op een enum in C #?


2565
2017-08-27 03:58


oorsprong


antwoorden:


Van een string:

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.")

Van een int:

YourEnum foo = (YourEnum)yourInt;

Bijwerken:

Van nummer kun je ook

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

3115
2017-08-27 03:59



Gewoon casten:

MyEnum e = (MyEnum)3;

U kunt controleren of het bereik binnen bereik is Enum.IsDefined:

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

718
2017-08-27 04:01



U kunt ook een uitbreidingsmethode gebruiken in plaats van een one-liner:

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

Gebruik:

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

OF

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

197
2017-11-11 13:27



Ik denk dat om een ​​volledig antwoord te krijgen, mensen moeten weten hoe enums intern werken in .NET.

Hoe dingen werken

Een enum in .NET is een structuur die een reeks waarden (velden) toewijst aan een basistype (de standaardinstelling is int). U kunt echter ook het integrale type kiezen dat door uw Enum wordt toegewezen aan:

public enum Foo : short

In dit geval wordt het enum toegewezen aan de short gegevenstype, wat betekent dat het in het geheugen wordt opgeslagen als een kort bericht en zich als een kort bericht zal gedragen wanneer u het cast en gebruikt.

Als je het vanuit IL-perspectief bekijkt, ziet een (normale, int) enum er als volgt uit:

.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__
}

Wat hier je aandacht zou moeten krijgen is dat het value__ wordt apart van de waardenwaarden opgeslagen. In het geval van het opsommingsteken Foo hierboven, het type value__ is int16. Dit betekent in feite dat je alles kunt opslaan wat je wilt in een enum, zolang de typen overeenkomen.

Op dit punt wil ik erop wijzen dat System.Enum is een waardetype, wat in feite betekent dat BarFlag zal 4 bytes opnemen in het geheugen en Foo zal 2 opnemen - b.v. de grootte van het onderliggende type (het is eigenlijk ingewikkelder dan dat, maar hey ...).

Het antwoord

Dus als u een geheel getal hebt dat u naar een enum wilt toewijzen, hoeft de runtime maar 2 dingen te doen: kopieer de 4 bytes en noem het iets anders (de naam van de enum). Kopiëren is impliciet omdat de gegevens worden opgeslagen als waardetype - dit betekent in feite dat als u niet-beheerde code gebruikt, u eenvoudig enums en gehele getallen kunt uitwisselen zonder gegevens te kopiëren.

Om het veilig te maken, denk ik dat het een goede gewoonte is om dit te doen weet dat de onderliggende typen hetzelfde of impliciet converteerbaar zijn en om ervoor te zorgen dat de enum-waarden bestaan ​​(deze worden standaard niet gecontroleerd!).

Probeer de volgende code om te zien hoe dit werkt:

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

Merk op dat casten naar e2 werkt ook! Vanuit het perspectief van de compiler hierboven is dit logisch: het value__ veld is gewoon gevuld met 5 of 6 en wanneer Console.WriteLine calls ToString(), de naam van e1 is opgelost terwijl de naam van e2 is niet.

Als dat niet is wat u van plan was, gebruik dan Enum.IsDefined(typeof(MyEnum), 6) om te controleren of de waarde die u aan het casten bent, wordt toegewezen aan een gedefinieerde opsomming.

Merk ook op dat ik expliciet ben over het onderliggende type van het enum, hoewel de compiler dit feitelijk controleert. Ik doe dit om te zorgen dat ik onderweg geen verrassingen tegenkom. Om deze verrassingen in actie te zien, kunt u de volgende code gebruiken (eigenlijk heb ik dit veel zien gebeuren in de databasecode):

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

116
2018-04-03 07:39



Neem het volgende voorbeeld:

int one = 1;
MyEnum e = (MyEnum)one;

89
2017-08-27 04:00



Ik gebruik dit stukje code om int in mijn enum te plaatsen:

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

Ik vind het de beste oplossing.


54
2017-10-21 10:05



Hieronder is een aardige utiliteitsklasse voor 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;
    }
}

44
2017-09-07 04:42