convert an enum to another type of enum

前端 未结 15 1555
感动是毒
感动是毒 2020-11-30 02:36

I have an enum of for example \'Gender\' (Male =0 , Female =1) and I have another enum from a service which has its own Gender enum (Male =0

15条回答
  •  一整个雨季
    2020-11-30 03:13

    I wrote a set extension methods a while back that work for several different kinds of Enums. One in particular works for what you are trying to accomplish and handles Enums with the FlagsAttribute as well as Enums with different underlying types.

    public static tEnum SetFlags(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;
    }
    

    From there you can add other more specific extension methods.

    public static tEnum AddFlags(this Enum e, tEnum flags) where tEnum : IComparable
    {
        SetFlags(e, flags, true);
    }
    
    public static tEnum RemoveFlags(this Enum e, tEnum flags) where tEnum : IComparable
    {
        SetFlags(e, flags, false);
    }
    

    This one will change types of Enums like you are trying to do.

    public static tEnum ChangeType(this Enum e) where tEnum : IComparable
    {
        return SetFlags(e, default(tEnum), true, false);
    }
    

    Be warned, though, that you CAN convert between any Enum and any other Enum using this method, even those that do not have flags. For example:

    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();
    }
    

    The variable turtle will have a value of Turtle.Blue.

    However, there is safety from undefined Enum values using this method. For instance:

    static void Main(string[] args)
    {
        Turtle turtle = Turtle.Yellow;
        WriteAccess access = turtle.ChangeType();
    }
    

    In this case, access will be set to WriteAccess.ReadWrite, since the WriteAccess Enum has a maximum value of 3.

    Another side effect of mixing Enums with the FlagsAttribute and those without it is that the conversion process will not result in a 1 to 1 match between their values.

    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();
    }
    

    In this case, letters will have a value of Letters.H instead of Letters.D, since the backing value of Flavors.Peach is 8. Also, a conversion from Flavors.Cherry | Flavors.Grape to Letters would yield Letters.C, which can seem unintuitive.

提交回复
热议问题