In this post i will expose a little solution to make it more easy to read different values stored in a single enum instance. This sample is written in C# 2.0 using iterators and operator overriding.
Let's use a simple enum definition:
[Flags] public enum Day { None = 0, Monday = 1, Tuesday = 2, Wednesday = 4, Thursday = 8, Friday = 16, Saturday = 32, Sunday = 64 };
Just a simple reminder:
The idea is to provide an enumeration on the different values of the set. The Enum class provides static methods to pass from Enums to integers. This is obligatory because a simple cast is not allowed from T.Let's try to implement this in a simple method.
private IEnumerable<T> GetEnumeration<T>(T values) { if (!typeof(T).IsSubclassOf(typeof(Enum))) throw new Exception("Must be an Enum"); int[] allValues = (int[])Enum.GetValues(typeof(T)); int intValues = Convert.ToInt32(values); foreach (int i in allValues) { if ((i & intValues) != 0) yield return (T)Enum.ToObject(typeof(T), i); } } Day weekend = Day.Saturday | Day.Sunday; foreach (Day d in GetEnumeration<Day>(weekend)) Console.WriteLine(d);
public struct MyEnum<T> : IEnumerable<T> { public MyEnum(T value) { _value = value; } private T _value; #region IEnumerable<T> Members IEnumerator<T> IEnumerable<T>.GetEnumerator() { if (!typeof(T).IsSubclassOf(typeof(Enum))) throw new Exception("Must be an Enum"); int[] allValues = (int[])Enum.GetValues(typeof(T)); int intValues = Convert.ToInt32(_value); foreach (int i in allValues) { if ((i & intValues) != 0) yield return (T)Enum.ToObject(typeof(T), i); } } public override string ToString() { return _value.ToString(); } } MyEnum<Day> weekend = new MyEnum<Day>(Day.Saturday | Day.Sunday); foreach (Day d in weekend) Console.WriteLine(d);
public struct MyEnum<T> : IEnumerable<T> { ... public static implicit operator T(MyEnum<T> e) { return e._value; } public static implicit operator MyEnum<T>(T e) { return new MyEnum<T>(e); } public static MyEnum<T> FromEnumerable(IEnumerable<T> e) { int value = 0; foreach (T t in e) { value |= Convert.ToInt32(t); } return (T)Enum.ToObject(typeof(T), value); } } MyEnum<Day> weekend = Day.Saturday | Day.Sunday; foreach (Day d in weekend) Console.WriteLine(d); Day d2 = weekend;
All the code we have seen requires C# 2.0. Using C# 3 available in the Linq preview, we have a huge advantage for free: C# 3 extends any IEnumerable<T> with a bunch of new methods. So we can use all set methods with MyEnum<T>. (Intersect, Union, ...). The result values are IEnumerable<T>. That's why we need to add a FromEnumerable method to go back to MyEnum<T>.
//Only works with C# 3 MyEnum<Day> weekend = Day.Saturday | Day.Sunday; MyEnum<Day> set1 = Day.Thursday | Day.Wednesday | Day.Saturday; IEnumerable<Day> result = weekend.Intersect(set1); Day commonValues = MyEnum<Day>.FromEnumerable(result);
Mitsu