web-dev-qa-db-fra.com

convertir une liste en un autre type d'énumération

J'ai une énumération de par exemple 'Gender' (Male =0 , Female =1) et une autre énumération d'un service qui a sa propre énumération de genre (Male =0 , Female =1, Unknown =2

Ma question est comment puis-je écrire quelque chose de rapide et Nice pour convertir de leur enum à la mienne?

95
kurasa

Utiliser une méthode d'extension fonctionne assez bien avec les deux méthodes de conversion suggérées par Nate:

public static class TheirGenderExtensions
{
    public static MyGender ToMyGender(this TheirGender value)
    {
        // insert switch statement here
    }
}

public static class MyGenderExtensions
{
    public static TheirGender ToTheirGender(this MyGender value)
    {
        // insert switch statement here
    }
}

De toute évidence, il n'est pas nécessaire d'utiliser des classes séparées si vous ne le souhaitez pas. Ma préférence est de garder les méthodes d'extension groupées par les classes/structures/énumérations auxquelles elles s'appliquent.

70
Zooba

Étant donné Enum1 value = ..., alors si vous voulez dire par nom:

Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());

Si vous voulez dire par valeur numérique, vous pouvez généralement simplement lancer:

Enum2 value2 = (Enum2)value;

(avec le casting, vous pouvez utiliser Enum.IsDefined pour vérifier les valeurs valides, cependant)

166
Marc Gravell

Il suffit de transtyper un pour int puis de le rediriger vers l'autre énumération (en considérant que vous souhaitez que le mappage soit effectué en fonction de la valeur):

Gender2 gender2 = (Gender2)((int)gender1);
43
Adrian Zanescu

Par souci de rigueur, je crée normalement une paire de fonctions, une qui prend Enum 1 et renvoie Enum 2 et une autre qui prend Enum 2 et renvoie Enum 1. Chacune consiste en une instruction case mappant les entrées sur les sorties et le cas par défaut lève une exception avec un message se plaindre d'une valeur inattendue.

Dans ce cas particulier, vous pourriez tirer parti du fait que les valeurs entières de Masculin et Féminin sont identiques, mais je l’éviterais, car c’est hackish et susceptible d’être cassé si l’énumération change à l’avenir.

20
Nate C-K

Vous pourriez écrire une méthode d'extension générique simple comme celle-ci

public static T ConvertTo<T>(this object value)            
    where T : struct,IConvertible
{
    var sourceType = value.GetType();
    if (!sourceType.IsEnum)
        throw new ArgumentException("Source type is not enum");
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Destination type is not enum");
    return (T)Enum.Parse(typeof(T), value.ToString());
}
13
Jishnu A P

Si nous avons:

enum Gender
{
    M = 0,
    F = 1,
    U = 2
}

et

enum Gender2
{
    Male = 0,
    Female = 1,
    Unknown = 2
}

Nous pouvons faire en toute sécurité

var gender = Gender.M;
var gender2   = (Gender2)(int)gender;

Ou même

var enumOfGender2Type = (Gender2)0;

Si vous souhaitez couvrir le cas où une énumération du côté droit du signe '=' a plus de valeurs que celle située du côté gauche, vous devrez écrire votre propre méthode/dictionnaire pour couvrir cela comme suggéré par d'autres.

11
Nedcode

vous pourriez écrire une fonction simple comme celle-ci:

public static MyGender ConvertTo(TheirGender theirGender)
{
    switch(theirGender)
    {
        case TheirGender.Male:
            break;//return male
        case TheirGender.Female:
            break;//return female
        case TheirGender.Unknown:
            break;//return whatever
    }
}
7
RCIX

Voici une version de la méthode d'extension si quelqu'un est intéressé

public static TEnum ConvertEnum<TEnum >(this Enum source)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true);
    }

// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();
5
Justin

Il y a quelque temps, j’ai écrit des méthodes d’extension définies qui fonctionnent pour différents types de Enums. L'une en particulier fonctionne pour ce que vous essayez d'accomplir et traite Enums avec les FlagsAttribute ainsi que Enums avec différents types sous-jacents.

public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable
{
    if (typeCheck)
    {
        if (e.GetType() != flags.GetType())
            throw new ArgumentException("Argument is not the same type as this instance.", "flags");
    }

    var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum));

    var firstNum = Convert.ToUInt32(e);
    var secondNum = Convert.ToUInt32(flags);

    if (set)
        firstNum |= secondNum;

    else
        firstNum &= ~secondNum;

    var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType);

    if (!typeCheck)
    {
        var values = Enum.GetValues(typeof(tEnum));
        var lastValue = (tEnum)values.GetValue(values.Length - 1);

        if (newValue.CompareTo(lastValue) > 0)
            return lastValue;
    }

    return newValue;
}

De là, vous pouvez ajouter d'autres méthodes d'extension plus spécifiques.

public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
    SetFlags(e, flags, true);
}

public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
    SetFlags(e, flags, false);
}

Celui-ci changera les types de Enums que vous essayez de faire.

public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
    return SetFlags(e, default(tEnum), true, false);
}

Soyez averti, cependant, que vous POUVEZ convertir entre toute Enum et toute autre Enum en utilisant cette méthode, même ceux qui n'ont pas d'indicateur. Par exemple:

public enum Turtle
{
    None = 0,
    Pink,
    Green,
    Blue,
    Black,
    Yellow
}

[Flags]
public enum WriteAccess : short
{
   None = 0,
   Read = 1,
   Write = 2,
   ReadWrite = 3
}

static void Main(string[] args)
{
    WriteAccess access = WriteAccess.ReadWrite;
    Turtle turtle = access.ChangeType<Turtle>();
}

La variable turtle aura la valeur Turtle.Blue.

Cependant, il existe une sécurité contre les valeurs Enum non définies à l'aide de cette méthode. Par exemple:

static void Main(string[] args)
{
    Turtle turtle = Turtle.Yellow;
    WriteAccess access = turtle.ChangeType<WriteAccess>();
}

Dans ce cas, access sera défini sur WriteAccess.ReadWrite, étant donné que WriteAccessEnum a une valeur maximale de 3.

Un autre effet secondaire du mélange de Enums avec FlagsAttribute et ceux qui ne le font pas est que le processus de conversion ne donnera pas une correspondance 1: 1 entre leurs valeurs.

public enum Letters
{
    None = 0,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H
}

[Flags]
public enum Flavors
{
    None = 0,
    Cherry = 1,
    Grape = 2,
    Orange = 4,
    Peach = 8
}

static void Main(string[] args)
{
    Flavors flavors = Flavors.Peach;
    Letters letters = flavors.ChangeType<Letters>();
}

Dans ce cas, letters aura une valeur de Letters.H au lieu de Letters.D, puisque la valeur de support de Flavors.Peach est 8. De plus, une conversion de Flavors.Cherry | Flavors.Grape en Letters donnerait Letters.C, ce qui peut sembler non intuitif.

1
Thick_propheT

Vous pouvez utiliser ToString () pour convertir le premier enum en son nom, puis Enum.Parse () pour reconvertir la chaîne en un autre enum. Cela lève une exception si la valeur n’est pas prise en charge par l’énumération de destination (c’est-à-dire pour une valeur "inconnue")

0
Jason Williams

Basé sur Justin's réponse ci-dessus, je suis venu avec ceci:

    /// <summary>
    /// Converts Enum Value to different Enum Value (by Value Name) See https://stackoverflow.com/a/31993512/6500501.
    /// </summary>
    /// <typeparam name="TEnum">The type of the enum to convert to.</typeparam>
    /// <param name="source">The source enum to convert from.</param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public static TEnum ConvertTo<TEnum>(this Enum source)
    {
        try
        {
            return (TEnum) Enum.Parse(typeof(TEnum), source.ToString(), ignoreCase: true);
        }
        catch (ArgumentException aex)
        {
            throw new InvalidOperationException
            (
                $"Could not convert {source.GetType().ToString()} [{source.ToString()}] to {typeof(TEnum).ToString()}", aex
            );
        }
    }
0
Sam Jazz

Je sais que c'est une vieille question et j'ai beaucoup de réponses. Cependant, je trouve que l'utilisation d'un énoncé de commutateur comme dans la réponse acceptée est un peu lourde, alors voici mes 2 centimes:

Ma méthode préférée personnelle consiste à utiliser un dictionnaire, où la clé est l'énumération source et la valeur, l'énumération cible. Ainsi, dans le cas présenté sur la question, mon code ressemblerait à ceci:

var genderTranslator = new Dictionary<TheirGender, MyGender>();
genderTranslator.Add(TheirGender.Male, MyGender.Male);
genderTranslator.Add(TheirGender.Female, MyGender.Female);
genderTranslator.Add(TheirGender.Unknown, MyGender.Unknown);

// translate their to mine    
var myValue = genderTranslator[TheirValue];

// translate mine to their
var TheirValue = genderTranslator .FirstOrDefault(x => x.Value == myValue).Key;;

Bien entendu, cela peut être encapsulé dans une classe statique et utilisé comme méthode d'extension:

public static class EnumTranslator
{

    private static Dictionary<TheirGender, MyGender> GenderTranslator = InitializeGenderTranslator();

    private static Dictionary<TheirGender, MyGender> InitializeGenderTranslator()
    {
        var translator = new Dictionary<TheirGender, MyGender>();
        translator.Add(TheirGender.Male, MyGender.Male);
        translator.Add(TheirGender.Female, MyGender.Female);
        translator.Add(TheirGender.Unknown, MyGender.Unknown);
        return translator;
    }

    public static MyGender Translate(this TheirGender theirValue)
    {
        return GenderTranslator[theirValue];
    }

    public static TheirGender Translate(this MyGender myValue)
    {
        return GenderTranslator.FirstOrDefault(x => x.Value == myValue).Key;
    }

}
0
Zohar Peled
public static TEnum ConvertByName<TEnum>(this Enum source, bool ignoreCase = false) where TEnum : struct
{
    // if limited by lack of generic enum constraint
    if (!typeof(TEnum).IsEnum)
    {
        throw new InvalidOperationException("enumeration type required.");
    }

    TEnum result;
    if (!Enum.TryParse(source.ToString(), ignoreCase, out result))
    {
        throw new Exception("conversion failure.");
    }

    return result;
}
0
epistemophilic