C# extension methods for combining and using Enum type flags.
using System;
namespace Extensions
{
/// <summary>
/// Extension methods to make working with Enum values easier
/// </summary>
public static class EnumExtensions
{
/// <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;
var parsed = new Value(append, type);
if (parsed.Signed != null)
{
result = Convert.ToInt64(value) | (long)parsed.Signed;
}
// 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;
var parsed = new Value(remove, type);
if (parsed.Signed != null)
{
result = Convert.ToInt64(value) & ~(long)parsed.Signed;
}
// 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
var parsed = new Value(check, type);
return parsed.Signed != null &&
(Convert.ToInt64(value) & (long)parsed.Signed) == (long)parsed.Signed;
}
/// <summary>
/// Checks if an enumerated type is missing a value
/// </summary>
public static bool Missing<T>(this Enum obj, T value)
{
return !Has(obj, value);
}
/// <summary>
/// Internal class to simplfy narrowing values between a
/// ulong and long since either value should cover any
/// lesser value.
/// </summary>
private class Value
{
public readonly long? Signed;
// cached comparisons for tye to use
private static readonly Type _uInt64 = typeof(ulong);
private static readonly Type _uInt32 = typeof(long);
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 == _uInt32 || compare == _uInt64)
{
Unsigned = Convert.ToUInt64(value);
}
//otherwise, a long should cover anything else
else
{
Signed = Convert.ToInt64(value);
}
}
public ulong? Unsigned { get; set; }
}
}
}
// ----------------------------------------
// Example Usage
// ----------------------------------------
[Flags]
internal enum PermissionTypes
{
None = 0,
Read = 1,
Write = 2,
Modify = 4,
Delete = 8,
Create = 16,
All = Read | Write | Modify | Delete | Create
}
// start with a value
PermissionTypes permissions = PermissionTypes.Read | PermissionTypes.Write;
//then check for the values
bool canRead = permissions.Has(PermissionTypes.Read); // true
bool canWrite = permissions.Has(PermissionTypes.Write); // true
bool canDelete = permissions.Has(PermissionTypes.Delete); // false
//
// http://hugoware.net/blog/enumeration-extensions-2-0
//
//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