我有一个枚举,例如' Gender
'(Male =0 , Female =1
),我还有一个服务具有自己的性别枚举(Male =0 , Female =1, Unknown =2
)的另一个枚举
我的问题是我该如何快速而又好地将它们的枚举转换为我的枚举?
我有一个枚举,例如' Gender
'(Male =0 , Female =1
),我还有一个服务具有自己的性别枚举(Male =0 , Female =1, Unknown =2
)的另一个枚举
我的问题是我该如何快速而又好地将它们的枚举转换为我的枚举?
Answers:
当使用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
}
}
显然,如果您不想使用单独的类。我的首选是将扩展方法按适用的类/结构/枚举分组。
给定Enum1 value = ...
,那么如果您的名字是指:
Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());
如果用数字表示,通常可以强制转换为:
Enum2 value2 = (Enum2)value;
(不过,使用强制转换,您可能要使用它Enum.IsDefined
来检查有效值)
Enum.Tryparse
: Enum2 value2 = Enum.TryParse(value.ToString(), out Enum2 outValue) ? outValue : Enum2.Unknown;
这将使您可以处理不存在的输入值,Enum2
而无需调用Enum.IsDefined
或捕获ArgumentException
由抛出的s Enum.Parse
。请注意,参数的顺序与或多或少相反Enum.Parse
。
只需将一个转换为int然后将其转换为另一个枚举(考虑到您希望基于值完成映射):
Gender2 gender2 = (Gender2)((int)gender1);
long
(或ulong
)支持,而不是由int
定义在上方int.MaxValue
(或下方)的成员支持int.MinValue
),在这种情况下,强制转换为int
可能会溢出,最终您会得到一个未定义的枚举值,该值应该定义。
如果我们有:
enum Gender
{
M = 0,
F = 1,
U = 2
}
和
enum Gender2
{
Male = 0,
Female = 1,
Unknown = 2
}
我们可以放心地做
var gender = Gender.M;
var gender2 = (Gender2)(int)gender;
甚至
var enumOfGender2Type = (Gender2)0;
如果要涵盖'='右侧的枚举比左侧的枚举具有更多值的情况-您将必须编写自己的方法/词典以按照其他建议进行覆盖。
您可以编写一个像这样的简单通用扩展方法
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());
}
您可以编写一个简单的函数,如下所示:
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
}
}
如果有人感兴趣,这是扩展方法版本
public static TEnum ConvertEnum<TEnum >(this Enum source)
{
return (TEnum)Enum.Parse(typeof(TEnum), source.ToString(), true);
}
// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();
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;
}
不久前,我写了一套扩展方法,可用于几种不同的Enum
s。一个特别的作品要尝试什么来完成和手柄Enum
有s FlagsAttribute
以及Enum
与不同的底层类型秒。
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;
}
从那里您可以添加其他更具体的扩展方法。
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);
}
这将Enum
像您尝试的那样更改s的类型。
public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
return SetFlags(e, default(tEnum), true, false);
}
但是请注意,您可以使用此方法在任何Enum
其他对象之间进行转换Enum
,即使那些没有标志的对象也可以转换。例如:
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>();
}
该变量turtle
的值为Turtle.Blue
。
但是,Enum
使用此方法可以确保未定义值的安全性。例如:
static void Main(string[] args)
{
Turtle turtle = Turtle.Yellow;
WriteAccess access = turtle.ChangeType<WriteAccess>();
}
在这种情况下,access
将设为WriteAccess.ReadWrite
,因为的WriteAccess
Enum
最大值为3。
将Enum
s与FlagsAttribute
和混合的另一种副作用是,转换过程不会导致s与它们之间的一对一匹配。
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>();
}
在这种情况下,letters
将具有Letters.H
而不是的值Letters.D
,因为后备值为Flavors.Peach
8。此外,从Flavors.Cherry | Flavors.Grape
到的转换Letters
将产生Letters.C
,这似乎是不直观的。
基于以上贾斯汀的回答,我想到了:
/// <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
);
}
}
我知道这是一个古老的问题,并且有很多答案,但是我发现,使用已接受答案中的switch语句有点麻烦,所以这里是我的2美分:
我个人最喜欢的方法是使用字典,其中的键是源枚举,值是目标枚举-因此,在出现问题的情况下,我的代码如下所示:
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;;
当然,可以将其包装在静态类中并用作扩展方法:
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;
}
}