Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if an Enum value is NOT a composite in C#

EDIT:

Most people suggest that flag enums should always have values of powers of two. That may be best practice but I am not defining enums here, rather checking them and want to cover all possible scenarios within reason. The question is really about the proper way to implement the function named EnumUtilities.IsValueDefinedAndComposite<T>.

ORIGINAL POST:

Consider the following Enum:

[Flags]
public enum TestWithFlags { One = 1, Two = 2, }

Following is the result of Enum.IsDefined with various values casted as TestWithFlags.

Output:

(1). Defined: True:  One.
(2). Defined: True:  Two.
(3). Defined: False: 100.
(4). Defined: False: One, Two.
(5). Defined: ?????: One, Two.

What I can't figure out is how to determine is an enum value is composite. Please see the function EnumUtilities.IsValueDefinedAndComposite<T> in the code below.

Here is the full 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; // True.
            Console.WriteLine("(1). Defined: {0}:  {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());

            value = TestWithFlags.Two; // True.
            Console.WriteLine("(2). Defined: {0}:  {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());

            value = (TestWithFlags) 100; // False.
            Console.WriteLine("(3). Defined: {0}: {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());

            value = TestWithFlags.One | TestWithFlags.Two; // False.
            Console.WriteLine("(4). Defined: {0}: {1}.", Enum.IsDefined(typeof(TestWithFlags), value), value.ToString());

            value = TestWithFlags.One | TestWithFlags.Two; // Not implemented.
            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;
            //var result = values.Count(v => (value | v) == value) > 1;
            // How to determine whether the argument [value] is composite.

            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));
            }
        }
    }
}
like image 990
Raheel Khan Avatar asked Feb 12 '23 15:02

Raheel Khan


1 Answers

You can try something like (Not Tested!):

   public static bool IsValueDefinedAndComposite<T>(T value)
        where T : struct, IComparable, IFormattable, IConvertible
    {
        EnumUtilities.ThrowOnEnumWithoutFlags<T>();

        var values = EnumUtilities.GetValues<T>();


        var result = values.OfType<T>().Contains(value);
        //var result = values.Count(v => (value | v) == value) > 1;
        // How to determine whether the argument [value] is composite.

        return (result);
    }

Basically, it is just checking if the value argument is part of the values, and if it is not, it is a composite.

like image 188
Avi Turner Avatar answered Feb 15 '23 10:02

Avi Turner