我写这个答案是因为我认为已经提供的大多数答案都存在根本问题,而可接受的答案并不完整。
按枚举整数值映射
这种方法不好,因为它假定MyGender 和TheirGender 的整数值将始终保持可比性。实际上,即使在单个项目中也很少能保证这一点,更不用说单独的服务了。
我们采用的方法应该可以用于其他枚举映射情况。我们永远不应该假设一个枚举与另一个枚举具有相同的关系——尤其是当我们可能无法控制一个或另一个时。
按枚举字符串值映射
这样会好一些,因为MyGender.Male 仍然会转换为TheirGender.Male,即使整数表示发生了变化,但仍然不理想。
我不鼓励这种方法,因为它假定名称值不会改变,并且始终保持不变。考虑到未来的增强功能,您不能保证会是这种情况;考虑是否添加了MyGender.NotKnown。您可能希望将其映射到 TheirGender.Unknown,但这不受支持。
此外,假设一个枚举按名称等同于另一个枚举通常是不好的,因为在某些情况下可能并非如此。如前所述,理想的方法适用于其他枚举映射要求。
显式映射枚举
这种方法使用 switch 语句将MyGender 显式映射到TheirGender。
这样比较好:
- 涵盖基础整数值发生变化的情况。
- 涵盖枚举名称更改的情况(即没有假设 - 开发人员需要更新代码以处理该场景 - 很好)。
- 处理无法映射枚举值的情况。
- 处理添加了新枚举值且默认情况下无法映射的情况(同样,没有做出任何假设 - 很好)。
- 可以轻松更新以支持
MyGender 或 TheirGender 的新枚举值。
- 可以对所有枚举映射要求采用相同的方法。
假设我们有以下枚举:
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));
}
}
}
如果你使用的是 C#8,你可以使用 syntax for switch expressions 和 expression bodies 来整理代码:
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))
};
}
如果您只在一个类中映射枚举,那么扩展方法可能会过大。在这种情况下,可以在类本身中声明该方法。
此外,如果映射只发生在单个方法中,那么您可以将其声明为local function:
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))
};
}
Here's a dotnet fiddle link with the above example.
tl;博士:
不要:
做:
- 使用 switch 语句显式映射枚举
- 当值不能被映射而不是返回 null 时抛出异常
- 考虑使用扩展方法