views:

593

answers:

2

Hey All,

I have decided it is impossible to do the following (equivalent) enum operations via reflection - as the Enum class has no operators, and nor does the emitted code expose any operators:

object boxedEnum = MyEnum.Flag1 | MyEnum.Flag2;
boxedEnum &= ~MyEnum.Flag2; // Remove the flag.

So I am currently doing the following (equivalent):

int boxedEnumValue = (int) boxedEnum;
boxedEnumValue &= ~MyEnum.Flag2;
boxedEnum = Enum.ToObject(boxedEnum.GetType(), boxedEnumValue);

Which works fine, the only problem is that the equivalent code to turn the boxedEnum into an integer is:

int boxedEnumValue = int.Parse(Enum.Format(boxedEnum.GetType(), boxedEnum, "X"), System.Globalization.NumberStyles.HexNumber);

Which I am sure you will agree is terrible and hacky.

So this question has two prongs. It would be awesome if someone could prove me wrong and provide a means to perform binary operations on boxed enums - otherwise any way to avoid the string round-trip would be appreciated.

Guffa gave me what I needed in order to convert the enum to a specific type. I authored an extension method that does the nitty-gritties:

    /// <summary>
    /// Gets the integral value of an enum.
    /// </summary>
    /// <param name="value">The enum to get the integral value of.</param>
    /// <returns></returns>
    public static T ToIntegral<T>(this object value)
    {
        if(object.ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        Type rootType = value.GetType();
        if (!rootType.IsEnum)
            throw new ArgumentOutOfRangeException("value", "value must be a boxed enum.");
        Type t = Enum.GetUnderlyingType(rootType);

        switch (t.Name.ToUpperInvariant())
        {
            case "SBYTE":
                return (T)Convert.ChangeType((sbyte) value, typeof(T));
            case "BYTE":
                return (T) Convert.ChangeType((byte) value, typeof(T));
            case "INT16":
                return (T) Convert.ChangeType((Int16) value, typeof(T));
            case "UINT16":
                return (T) Convert.ChangeType((UInt16) value, typeof(T));
            case "INT32":
                return (T) Convert.ChangeType((Int32) value, typeof(T));
            case "UINT32":
                return (T) Convert.ChangeType((UInt32) value, typeof(T));
            case "INT64":
                return (T) Convert.ChangeType((Int64) value, typeof(T));
            case "UINT64":
                return (T) Convert.ChangeType((UInt64) value, typeof(T));
            default:
                throw new NotSupportedException();
        }
    }
A: 
int enumValue = (int)SomeEnum.Val1 | (int)SomeEnum.Val2;
SomeEnum e = (SomeEnum)enumValue;

Do you want to achieve something like this?

Kirtan
The enum is boxed. You have to unbox it before casting to an int.
Jonathan C Dickinson
+5  A: 

A boxed value can never be changed in place. You just have to unbox the enum, do the operation and box it again:

boxedEnum = (MyEnum)boxedEnum & ~MyEnum.Flag2;

Edit:

Provided that the underlying type of the enum is int, you can just unbox it to int and box it to int. The boxed int can later on be unboxed to the enum type:

boxedEnum = (int)boxedEnum & ~2;

MyEnum value = (MyEnum)boxedEnum; // works both for a boxed int and a boxed MyEnum
Guffa
Unfortunately I can't. It is a helper method that needs to accept any kind of enum.
Jonathan C Dickinson
Provided that the underlying type of the enum is int, you can just unbox it to int and box it to int. The boxed int can later on be unboxed to the enum type.
Guffa
@Guffa you genius! Can you edit your answer so that I can accept it please.
Jonathan C Dickinson