我有一个枚举类型,比如 'Gender
' (Male =0 , Female =1
),另外我还有一个服务中的枚举类型,它有自己的 Gender 枚举类型 (Male =0 , Female =1, Unknown =2
)
我的问题是如何快速而好地编写代码将其枚举类型转换为我的枚举类型?
我有一个枚举类型,比如 'Gender
' (Male =0 , Female =1
),另外我还有一个服务中的枚举类型,它有自己的 Gender 枚举类型 (Male =0 , Female =1, Unknown =2
)
我的问题是如何快速而好地编写代码将其枚举类型转换为我的枚举类型?
如果给定 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
或捕获 Enum.Parse
抛出的 ArgumentException
。请注意,参数的顺序与 Enum.Parse
相比更多或更少被颠倒了。 - Sander使用扩展方法非常方便,当使用 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
}
}
如果您不想使用单独的类,显然没有必要这样做。我更喜欢将扩展方法按它们适用于的类别/结构/枚举进行分组。
将一个枚举类型先转换为int类型,然后再转换为另一个枚举类型(假设你希望根据值进行映射):
只需将一个枚举类型先转换为int类型,再将其转换为另一个枚举类型即可(假设您希望基于值进行映射):
Gender2 gender2 = (Gender2)((int)gender1);
long
(或ulong
)支持的,而不是由int
支持的,其成员定义高于int.MaxValue
(或低于int.MinValue
),在这种情况下进行int
强制转换可能会溢出,导致未定义的枚举值。 - Rich O'Kelly如果我们有:
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;
如果您想覆盖枚举值在左侧的 "=" 符号右侧具有更多值的情况,那么您将不得不编写自己的方法/字典来覆盖,就像其他人建议的那样。
如果您想覆盖枚举值在左侧的 "=" 符号右侧具有更多值的情况,那么您将不得不编写自己的方法/字典来覆盖,就像其他人建议的那样。
为了更加彻底,我通常会创建一对函数。一个接收枚举1并返回枚举2,另一个接收枚举2并返回枚举1。每个函数都由一个case语句组成,将输入映射到输出。如果默认情况下出现意外的值,则抛出异常并显示相关信息。
在这种特定情况下,您可以利用Male和Female的整数值相同这一事实,但我建议避免使用这种方法,因为它是hackish的。而且如果任何一个枚举类型在未来发生更改,此方法就会失效。
public enum MyGender
{
Male = 0,
Female = 1,
}
public enum TheirGender
{
Male = 0,
Female = 1,
Unknown = 2,
}
public MyGender GetMyGender(TheirGender theirGender)
{
switch (theirGender)
{
case TheirGender.Male:
return MyGender.Male;
case TheirGender.Female:
return MyGender.Female;
default:
throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender));
}
}
TheirGender?
),对于任何无法匹配的输入返回null。这是不好的,null并不等同于未知映射。如果无法映射输入,则应抛出异常,否则方法应该被命名得更加明确以反映其行为:public TheirGender? GetTheirGenderOrDefault(MyGender myGender)
{
switch (myGender)
{
case MyGender.Male:
return TheirGender.Male;
case MyGender.Female:
return TheirGender.Female;
default:
return default(TheirGender?);
}
}
额外考虑事项
如果有可能在解决方案的各个部分需要多次使用此方法,可以考虑创建一个扩展方法:
public static class TheirGenderExtensions
{
public static MyGender GetMyGender(this TheirGender theirGender)
{
switch (theirGender)
{
case TheirGender.Male:
return MyGender.Male;
case TheirGender.Female:
return MyGender.Female;
default:
throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender));
}
}
}
public static class TheirGenderExtensions
{
public static MyGender GetMyGender(this TheirGender theirGender)
=> theirGender switch
{
TheirGender.Male => MyGender.Male,
TheirGender.Female => MyGender.Female,
_ => throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender))
};
}
public static void Main()
{
Console.WriteLine(GetMyGender(TheirGender.Male));
Console.WriteLine(GetMyGender(TheirGender.Female));
Console.WriteLine(GetMyGender(TheirGender.Unknown));
static MyGender GetMyGender(TheirGender theirGender)
=> theirGender switch
{
TheirGender.Male => MyGender.Male,
TheirGender.Female => MyGender.Female,
_ => throw new InvalidEnumArgumentException(nameof(theirGender), (int)theirGender, typeof(TheirGender))
};
}
简而言之:
不要:
要:
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;
}