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?
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.
É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)
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);
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.
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());
}
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.
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
}
}
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>();
Il y a quelque temps, j’ai écrit des méthodes d’extension définies qui fonctionnent pour différents types de Enum
s. L'une en particulier fonctionne pour ce que vous essayez d'accomplir et traite Enum
s avec les FlagsAttribute
ainsi que Enum
s 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 Enum
s 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 WriteAccess
Enum
a une valeur maximale de 3.
Un autre effet secondaire du mélange de Enum
s 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.
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")
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
);
}
}
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;
}
}
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;
}