将枚举转换为另一种类型的枚举

kur*_*asa 108 c# enums

我有一个例如' Gender'(Male =0 , Female =1)的枚举,我有一个服务的另一个枚举,它有自己的性别枚举(Male =0 , Female =1, Unknown =2)

我的问题是我怎样才能快速而愉快地写出从枚举转换为我的东西?

Mar*_*ell 203

鉴于Enum1 value = ...,如果你的意思是:

Enum2 value2 = (Enum2) Enum.Parse(typeof(Enum2), value.ToString());
Run Code Online (Sandbox Code Playgroud)

如果你的意思是数值,你通常可以只是演员:

Enum2 value2 = (Enum2)value;
Run Code Online (Sandbox Code Playgroud)

(使用强制转换,您可能希望Enum.IsDefined用来检查有效值)

  • 这是更好的答案 (13认同)
  • 这是一个使用 `Enum.Tryparse` 的版本: `Enum2 value2 = Enum.TryParse(value.ToString(), out Enum2 outValue) ? outValue : Enum2.Unknown;` 这将允许您处理在 `Enum2` 中不存在的输入值,而无需调用 `Enum.IsDefined` 或捕获由 `Enum.Parse` 抛出的 `ArgumentException`。请注意,参数的顺序或多或少与“Enum.Parse”相反。 (4认同)

Zoo*_*oba 80

当使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,如果你不愿意,就不需要使用单独的类.我的偏好是将扩展方法按照它们适用的类/结构/枚举进行分组.


Adr*_*scu 45

只需将一个转换为int,然后将其转换为另一个枚举(考虑到您希望根据值完成映射):

Gender2 gender2 = (Gender2)((int)gender1);
Run Code Online (Sandbox Code Playgroud)

  • 虽然不太可能在野外看到它,并且性别极不可能如此,但是可能存在一些由"long"(或"ulong")而不是"int"支持的枚举.成员定义的成员高于`int.MaxValue`(或低于`int.MinValue`),在这种情况下,转换为`int`可能会溢出,你最终会得到一个应定义的未定义的枚举值. (3认同)
  • 这要求两个枚举以相同的顺序具有相同的值.虽然它解决了这个特定的问题,但这确实很脆弱,我不会将它用于枚举映射. (3认同)
  • 好吧......呃!.映射需要基于某些事情来完成.在这种情况下,映射是整数值.对于基于名称的映射,您需要不同的代码.对于另一种映射别的东西.没有人说这是"一般的枚举映射",除非你可以尝试指定"一般映射"的含义,否则这种情况不存在 (2认同)

Nat*_*C-K 20

为了彻底,我通常创建一对函数,一个接受Enum 1并返回Enum 2,另一个接受Enum 2并返回Enum 1.每个函数都包含一个case语句,将输入映射到输出,默认情况下抛出异常消息抱怨意外的价值.

在这种特殊情况下,你可以利用男性和女性的整数值是相同的这一事实,但我会避免这种情况,因为如果任何一个枚举在将来发生变化,它就会变得很破旧并且会受到破坏.

  • +1我见过许多开发人员放弃使用枚举的整数值转换它们的冲动,但这很容易出错.旧学校编写2个函数的方法随着时间的推移证明了它的价值...... (7认同)

Ned*_*ode 16

如果我们有:

enum Gender
{
    M = 0,
    F = 1,
    U = 2
}
Run Code Online (Sandbox Code Playgroud)

enum Gender2
{
    Male = 0,
    Female = 1,
    Unknown = 2
}
Run Code Online (Sandbox Code Playgroud)

我们可以安全地做

var gender = Gender.M;
var gender2   = (Gender2)(int)gender;
Run Code Online (Sandbox Code Playgroud)

甚至

var enumOfGender2Type = (Gender2)0;
Run Code Online (Sandbox Code Playgroud)

如果你想要覆盖'='符号右侧的枚举值比左侧枚举值更多的情况 - 你必须编写自己的方法/字典来覆盖其他人建议的内容.


Jis*_*A P 13

您可以编写一个这样的简单通用扩展方法

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());
}
Run Code Online (Sandbox Code Playgroud)


RCI*_*CIX 8

你可以编写一个简单的函数,如下所示:

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
    }
}
Run Code Online (Sandbox Code Playgroud)


Jus*_*tin 6

如果有人感兴趣,这是一个扩展方法版本

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

// Usage
NewEnumType newEnum = oldEnumVar.ConvertEnum<NewEnumType>();
Run Code Online (Sandbox Code Playgroud)


小智 5

我写这个答案是因为我相信已经提供的大多数答案都存在基本问题,而可接受的答案是不完整的。

按枚举整数值映射

这种做法是不好的,只是因为它假设两者的整数值MyGender,并TheirGender会一直保持相媲美。在实践中,即使在单个项目中也很少能保证这一点,更不用说单独的服务了。

我们采用的方法应该可以用于其他枚举映射情况。我们永远不应该假设一个枚举与另一个枚举相同 - 特别是当我们可能无法控制一个或另一个时。

按枚举字符串值映射

这要好一些,因为即使整数表示被更改,仍然MyGender.Male会转换为TheirGender.Male,但仍然不理想。

我不鼓励这种方法,因为它假定名称值不会改变,并且将始终保持相同。考虑到未来的增强功能,您不能保证会是这种情况;考虑是否MyGender.NotKnown添加。您可能希望将其映射到TheirGender.Unknown,但这将不受支持。

此外,假设一个枚举在名称上等同于另一个枚举通常是不好的,因为在某些情况下可能并非如此。如前所述,理想的方法适用于其他枚举映射要求。

显式映射枚举

这种方法明确映射MyGenderTheirGender使用 switch 语句。

这更好,因为:

  • 涵盖基础整数值更改的情况。
  • 涵盖枚举名称更改的情况(即没有假设 - 开发人员将需要更新代码以处理该场景 - 很好)。
  • 处理无法映射枚举值的情况。
  • 处理添加新枚举值并且默认情况下无法映射的情况(同样,没有做出任何假设 - 很好)。
  • 可以轻松更新以支持MyGender或 的新枚举值TheirGender
  • 对于所有枚举映射要求,可以采用相同的方法。

假设我们有以下枚举:

public enum MyGender
{
    Male = 0,
    Female = 1,
}

public enum TheirGender
{
    Male = 0,
    Female = 1,
    Unknown = 2,
}
Run Code Online (Sandbox Code Playgroud)

我们可以创建以下函数来“从他们的枚举转换为我的”:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

先前的答案建议返回一个可为空的枚举 ( 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?);
    }
}
Run Code Online (Sandbox Code Playgroud)

其他注意事项

如果在解决方案的各个部分中可能不止一次需要此方法,您可以考虑为此创建一个扩展方法:

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 C#8,您可以使用switch 表达式表达式主体语法来整理代码:

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))
        };
}
Run Code Online (Sandbox Code Playgroud)

如果您只在单个类中映射枚举,那么扩展方法可能有点过分。在这种情况下,该方法可以在类本身中声明。

此外,如果映射只会在单个方法中发生,那么您可以将其声明为本地函数

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))
        };
}
Run Code Online (Sandbox Code Playgroud)

这是上面示例的 dotnet fiddle 链接

tl;博士:

不要:

  • 按整数值映射枚举
  • 按名称映射枚举

做:

  • 使用 switch 语句显式映射枚举
  • 当值无法映射而不是返回 null 时抛出异常
  • 考虑使用扩展方法