Convert.ChangeType und Konvertieren in Aufzählungen?

70

Ich habe einen Int16Wert aus der Datenbank erhalten und muss diesen in einen Aufzählungstyp konvertieren. Dies geschieht leider in einer Ebene des Codes, die nur sehr wenig über die Objekte weiß, außer was sie durch Reflexion sammeln können.

Als solches wird ein Aufruf ausgeführt, Convert.ChangeTypeder mit einer ungültigen Besetzungsausnahme fehlschlägt.

Ich fand eine meiner Meinung nach stinkende Problemumgehung wie folgt:

String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);

Gibt es einen besseren Weg, damit ich mich nicht durch diese String-Operation bewegen muss?

Hier ist ein kurzes, aber vollständiges Programm, das verwendet werden kann, wenn jemand experimentieren muss:

using System;

public class MyClass
{
    public enum DummyEnum
    {
        Value0,
        Value1
    }

    public static void Main()
    {
        Int16 value = 1;
        Type destinationType = typeof(DummyEnum);

        String name = Enum.GetName(destinationType, value);
        Object enumValue = Enum.Parse(destinationType, name, false);

        Console.WriteLine("" + value + " = " + enumValue);
    }
}
Lasse V. Karlsen
quelle
1
Autsch ... Ich muss aufhören zu versuchen, Fragen wie diese zu beantworten, bevor ich meinen Kaffee getrunken habe ...
Daniel Schaffer
Ich sehe jetzt, dass sich die Console.WriteLine auch in einer Ebene befindet, die keinen Zugriff auf den Aufzählungstyp hat. Ich habe das völlig missverstanden. Meine (dumme) Antwort gelöscht.
GvS

Antworten:

92

Enum.ToObject(.... ist was du suchst!

C #

StringComparison enumValue = (StringComparison)Enum.ToObject(typeof(StringComparison), 5);

VB.NET

Dim enumValue As StringComparison = CType([Enum].ToObject(GetType(StringComparison), 5), StringComparison)

Wenn Sie viel Enum-Konvertierung durchführen und versuchen, die folgende Klasse zu verwenden, sparen Sie viel Code.

public class Enum<EnumType> where EnumType : struct, IConvertible
{

    /// <summary>
    /// Retrieves an array of the values of the constants in a specified enumeration.
    /// </summary>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType[] GetValues()
    {
        return (EnumType[])Enum.GetValues(typeof(EnumType));
    }

    /// <summary>
    /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType Parse(string name)
    {
        return (EnumType)Enum.Parse(typeof(EnumType), name);
    }

    /// <summary>
    /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
    /// </summary>
    /// <param name="name"></param>
    /// <param name="ignoreCase"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType Parse(string name, bool ignoreCase)
    {
        return (EnumType)Enum.Parse(typeof(EnumType), name, ignoreCase);
    }

    /// <summary>
    /// Converts the specified object with an integer value to an enumeration member.
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType ToObject(object value)
    {
        return (EnumType)Enum.ToObject(typeof(EnumType), value);
    }
}

Anstatt zu schreiben (StringComparison)Enum.ToObject(typeof(StringComparison), 5);, können Sie jetzt einfach schreiben Enum<StringComparison>.ToObject(5);.

Peter
quelle
4
Legende! Wusste nichts davon. Ist Stackoverflow nicht brillant?! :-)
Doktor Jones
Ich habe über eine Stunde lang mit einem ähnlichen Problem gekämpft und das hat es gelöst! Eine wohlverdiente +1 auch zwei Jahre nach der Veröffentlichung;)
Edurne Pascual
1
ToObject()scheint Werte zuzulassen, die in der Aufzählung nicht vorhanden sind, und auch Werte außerhalb des Bereichs des zugrunde liegenden Typs:Enum.ToObject(typeof(IntEnumType), (long)Int32.MaxValue + 1)
Nelson Rothermel
1
@ NelsonRothermel: C # selbst erlaubt Aufzählungswerte, die nicht in der Aufzählung definiert sind, also keine Überraschung. Ihr anderer Punkt ist genauer als das Casting, aber es scheint nur ein Sonderfall Ihres ersten Punktes zu sein (er scheint zuerst auf den zugrunde liegenden Typ zu werfen?)
Michael Bray
Ich habe diese Methode oft gesehen (in Intellisense), hatte aber eine Ahnung von ihrer Aufgabe. Die Designer hätten dieser Methode einen intuitiveren Namen geben können.
Zoltán Tamási
0

Basierend auf der Antwort von @ Peter ist hier die Methode Nullable<int>zur EnumKonvertierung:

public static class EnumUtils
{
        public static bool TryParse<TEnum>(int? value, out TEnum result)
            where TEnum: struct, IConvertible
        {
            if(!value.HasValue || !Enum.IsDefined(typeof(TEnum), value)){
                result = default(TEnum);
                return false;
            }
            result = (TEnum)Enum.ToObject(typeof(TEnum), value);
            return true;
        }
}

Die Verwendung EnumUtils.TryParse<YourEnumType>(someNumber, out result)wird für viele Szenarien nützlich. Beispielsweise verfügt WebApi Controller in Asp.NET nicht über einen Standardschutz gegen ungültige Enum-Parameter. Asp.NET wird nur verwenden default(YourEnumType)Wert, auch wenn einige Pässe null, -1000, 500000, "garbage string"oder vollständig die Parameter ignoriert. Darüber hinaus ist ModelStatein all diesen Fällen gültig, sodass eine der Lösungen darin besteht, den int?Typ mit benutzerdefinierter Prüfung zu verwenden

public class MyApiController: Controller
{
    [HttpGet]
    public IActionResult Get(int? myEnumParam){    
        MyEnumType myEnumParamParsed;
        if(!EnumUtils.TryParse<MyEnumType>(myEnumParam, out myEnumParamParsed)){
            return BadRequest($"Error: parameter '{nameof(myEnumParam)}' is not specified or incorrect");
        }      

        return this.Get(washingServiceTypeParsed);            
    }
    private IActionResult Get(MyEnumType myEnumParam){ 
       // here we can guarantee that myEnumParam is valid
    }
Artru
quelle
0

Wenn Sie eine Aufzählung in einer Datentabelle speichern, aber nicht wissen, welche Spalte eine Aufzählung und welche eine Zeichenfolge / int ist, können Sie auf folgende Weise auf den Wert zugreifen:

foreach (DataRow dataRow in myDataTable.Rows)
{
    Trace.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
    foreach (DataColumn dataCol in myDataTable.Columns)
    {
        object v = dataRow[dataCol];
        Type t = dataCol.DataType;
        bool e = false;
        if (t.IsEnum) e = true;

        Trace.WriteLine((dataCol.ColumnName + ":").PadRight(30) +
            (e ? Enum.ToObject(t, v) : v));
    }
}
Cassova
quelle