EDIT:
Most people believe that flag enumerations should always have the powers of two. This may be best practice, but I do not define the listings here, rather check them out and want to cover all possible scenarios within reasonable limits. The question really is the correct way to implement a function with a name EnumUtilities.IsValueDefinedAndComposite<T>.
ORIGINAL MAIL:
Consider the following Enum:
[Flags]
public enum TestWithFlags { One = 1, Two = 2, }
Below is the result Enum.IsDefinedwith various values cast as TestWithFlags.
Conclusion:
(1). Defined: True: One.
(2). Defined: True: Two.
(3). Defined: False: 100.
(4). Defined: False: One, Two.
(5). Defined: ?????: One, Two.
I cannot figure out how to determine if an enumeration value is composite. See Function EnumUtilities.IsValueDefinedAndComposite<T>in the code below.
Here is the complete code for convenience.
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyNamespace
{
[Flags]
public enum TestWithFlags { One = 1, Two = 2, }
public static class Program
{
private static void Main (string [] args)
{
TestWithFlags value;
value = TestWithFlags.One;
Console.WriteLine("(1). Defined: {0}: {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());
value = TestWithFlags.Two;
Console.WriteLine("(2). Defined: {0}: {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());
value = (TestWithFlags) 100;
Console.WriteLine("(3). Defined: {0}: {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());
value = TestWithFlags.One | TestWithFlags.Two;
Console.WriteLine("(4). Defined: {0}: {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());
value = TestWithFlags.One | TestWithFlags.Two;
Console.WriteLine("(5). Defined: N/A: {1}.", EnumUtilities.IsValueDefinedAndComposite(value), value.ToString());
Console.WriteLine();
Console.Write("Press any key to continue...");
Console.ReadKey(true);
}
}
public static class EnumUtilities
{
public static List<T> GetValues<T> ()
where T: struct, IComparable, IFormattable, IConvertible
{
EnumUtilities.ThrowOnNonEnum<T>();
var list = Enum.GetValues(typeof(T)).OfType<T>().ToList().ConvertAll<T>(v => ((T) v));
return (list);
}
public static bool IsValueDefinedAndComposite<T> (T value)
where T: struct, IComparable, IFormattable, IConvertible
{
EnumUtilities.ThrowOnEnumWithoutFlags<T>();
var values = EnumUtilities.GetValues<T>();
var result = false;
return (result);
}
public static bool IsValueDefinedAndNonComposite<T> (T value)
where T: struct, IComparable, IFormattable, IConvertible
{
EnumUtilities.ThrowOnNonEnum<T>();
return (Enum.IsDefined(typeof(T), value));
}
public static bool IsValueDefined<T> (T value)
where T: struct, IComparable, IFormattable, IConvertible
{
EnumUtilities.ThrowOnNonEnum<T>();
return (EnumUtilities.IsValueDefinedAndNonComposite(value) || EnumUtilities.IsValueDefinedAndComposite(value));
}
private static void ThrowOnNonEnum<T> ()
{
if (!typeof(T).IsEnum)
{
throw (new ArgumentException("The generic argument [<T>] must be an enumeration.", "T: " + typeof(T).FullName));
}
}
private static void ThrowOnEnumWithFlags<T> ()
{
EnumUtilities.ThrowOnNonEnum<T>();
var attributes = typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false);
if (attributes.Length > 0)
{
throw (new ArgumentException("The generic argument [<T>] must be an enumeration without the [FlagsAttribute] applied.", "T: " + typeof(T).FullName));
}
}
private static void ThrowOnEnumWithoutFlags<T> ()
{
EnumUtilities.ThrowOnNonEnum<T>();
var attributes = typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false);
if (attributes.Length == 0)
{
throw (new ArgumentException("The generic argument [<T>] must be an enumeration with the [FlagsAttribute] applied.", "T: " + typeof(T).FullName));
}
}
}
}