Enumeration Extensions 2.0
A while back I had posted some code about making it easier to work with enumerated types -- Especially with the Flags
attribute. An experienced programmer won't have a hard time understanding all the voodoo magic behind the the bitwise operators but for the rest of us then something a little easier to read is always welcome.
The problem with the previous code is that it was created to work with the project I was currently working on so I didn't put a lot of effort into making it work with multiple types. That said, below is the official version 2.0 of the EnumerationExtensions
class.
using System; namespace Extensions { /// <summary> /// Extension methods to make working with Enum values easier /// </summary> public static class EnumerationExtensions { #region Extension Methods /// <summary> /// Includes an enumerated type and returns the new value /// </summary> public static T Include<T>(this Enum value, T append) { Type type = value.GetType(); //determine the values object result = value; _Value parsed = new _Value(append, type); if (parsed.Signed is long) { result = Convert.ToInt64(value) | (long)parsed.Signed; } else if (parsed.Unsigned is ulong) { result = Convert.ToUInt64(value) | (ulong)parsed.Unsigned; } //return the final value return (T)Enum.Parse(type, result.ToString()); } /// <summary> /// Removes an enumerated type and returns the new value /// </summary> public static T Remove<T>(this Enum value, T remove) { Type type = value.GetType(); //determine the values object result = value; _Value parsed = new _Value(remove, type); if (parsed.Signed is long) { result = Convert.ToInt64(value) & ~(long)parsed.Signed; } else if (parsed.Unsigned is ulong) { result = Convert.ToUInt64(value) & ~(ulong)parsed.Unsigned; } //return the final value return (T)Enum.Parse(type, result.ToString()); } /// <summary> /// Checks if an enumerated type contains a value /// </summary> public static bool Has<T>(this Enum value, T check) { Type type = value.GetType(); //determine the values object result = value; _Value parsed = new _Value(check, type); if (parsed.Signed is long) { return (Convert.ToInt64(value) & (long)parsed.Signed) == (long)parsed.Signed; } else if (parsed.Unsigned is ulong) { return (Convert.ToUInt64(value) & (ulong)parsed.Unsigned) == (ulong)parsed.Unsigned; } else { return false; } } /// <summary> /// Checks if an enumerated type is missing a value /// </summary> public static bool Missing<T>(this Enum obj, T value) { return !EnumerationExtensions.Has<T>(obj, value); } #endregion #region Helper Classes //class to simplfy narrowing values between //a ulong and long since either value should //cover any lesser value private class _Value { //cached comparisons for tye to use private static Type _UInt64 = typeof(ulong); private static Type _UInt32 = typeof(long); public long? Signed; public ulong? Unsigned; public _Value(object value, Type type) { //make sure it is even an enum to work with if (!type.IsEnum) { throw new ArgumentException("Value provided is not an enumerated type!"); } //then check for the enumerated value Type compare = Enum.GetUnderlyingType(type); //if this is an unsigned long then the only //value that can hold it would be a ulong if (compare.Equals(_Value._UInt32) || compare.Equals(_Value._UInt64)) { this.Unsigned = Convert.ToUInt64(value); } //otherwise, a long should cover anything else else { this.Signed = Convert.ToInt64(value); } } } #endregion } }
This code results in a much easier to read syntax and is mildly better at avoiding type casting issues. Instead of defaulting to int
as the other version did, this version attempts to decide between Int64
or UInt64
since either could meet the requirements for any of their lesser counterparts.
Now we can use syntax similar like you see below...
//create the typical object RegexOptions options = RegexOptions.None; //Assign a value options = options.Include(RegexOptions.IgnoreCase); //options = IgnoreCase //Or assign multiple values options = options.Include(RegexOptions.Multiline | RegexOptions.Singleline); //options = IgnoreCase, Multiline, Singleline //Remove values from the list options = options.Remove(RegexOptions.IgnoreCase); //options = Multiline, Singleline //Check if a value even exists bool multiline = options.Has(RegexOptions.Multiline); //true bool ignoreCase = options.Missing(RegexOptions.IgnoreCase); //true
Anyways, a whole lot easier to read in my opinion. Enjoy!
February 23, 2010
Enumeration Extensions 2.0
Post titled "Enumeration Extensions 2.0"