Enum flag attribute C# - c#

i'be looked some same topics but havn't find what i'm looking for
I should use flag enum flag atribute and check if my data is in one of the collections of this enum
For example, enum:
[Flags]
private enum MyEnum {
Apple,
Orange,
Tomato,
Potato
Melon,
Watermelon,
Fruit = Apple | Orange,
Vegetable = Tomato | Potato,
Berry = Melon | Watermelon,
}
In the method i should check a input data. How can i do it?
private void Checking(string data){
if(MyEnum.Fruit contains data) MessageBox.Show("Fruit");
if(MyEnum.Vegetable contains data) MessageBox.Show("Vegetables");
if(MyEnum.Berry contains data) MessageBox.Show("Berry");
}
What should be instead of "contains data"?
UPDATE
private void ZZZ(){
Cheching("Apple");
}

First of, you need to manually number your values with the powers-of-2 sequence :
[Flags]
private enum MyEnum
{
None = 0, // often useful
Apple = 1,
Orange = 2,
Tomato = 4,
Potato = 8,
Melon = 16,
Watermelon = 32,
Fruit = Apple | Orange,
Vegetable = Tomato | Potato,
Berry = Melon | Watermelon,
}
The [Flags] attribute is not strictly necessary, it only controls the ToString() behaviour.
And to check whether a string matches your value you'll have to make it an enum first:
private void Checking(string data)
{
MyEnum v = (MyEnum) Enum.Parse(typeof(MyEnum), data);
if((MyEnum.Fruit & v) != 0) MessageBox.Show("It's a Fruit");
...
}
But do note that interchanging between Enum and string like this with Parse() is limited.

In addition to Henk Holterman's solution you may use extension methods:
[Flags]
private enum MyEnum {
None = 0,
Apple = 1,
Orange = 2,
Tomato = 4,
Potato = 8,
Melon = 16,
Watermelon = 32,
Berry = Melon | Watermelon,
Fruit = Apple | Orange,
Vegetable = Potato | Tomato
}
private static class MyEnumExtensions {
public static Boolean IsFruit(this MyEnum value) {
return (value & MyEnum.Fruit) == MyEnum.Fruit;
}
public static Boolean IsVegetable(this MyEnum value) {
return (value & MyEnum.Vegetable) == MyEnum.Vegetable;
}
public static Boolean IsBerry(this MyEnum value) {
return (value & MyEnum.Berry) == MyEnum.Berry;
}
}
...
MyEnum data = ...
if (data.IsBerry()) {
MessageBox.Show("Berry");
}

You also can use the HasFlag-method of the Enum-class. As Henk pointed out will need to assign the values to your enum manually using values of the powers-of-2 sequence.
[Flags]
private enum MyEnum
{
Apple = 1,
Orange = 2,
Tomato = 4,
Potato = 8,
Melon 16,
Watermelon = 32,
Fruit = Apple | Orange,
Vegetable = Tomato | Potato,
Berry = Melon | Watermelon,
}
Then, to check you could use the following method which is working for all composed parts of your enumeration:
void Cheking(string data)
{
// Get the enum value of the string passed to the method
MyEnum myEnumData;
if (Enum.TryParse<MyEnum>(data, out myEnumData))
{
// If the string was a valid enum value iterate over all the value of
// the underlying enum type
var values = Enum.GetValues(typeof(MyEnum)).OfType<MyEnum>();
foreach (var value in values)
{
// If the value is not a power of 2 it is a composed one. If it furthermore
// has the flag passed to the method this is one we searched.
var isPowerOfTwo = (value != 0) && ((value & (value - 1)) == 0);
if (!isPowerOfTwo && value.HasFlag(myEnumData))
{
MessageBox.Show(value.ToString());
}
}
}
// In case an invalid value had been passed to the method
// display an error message.
else
{
MessageBox.Show("Invalid Value");
}
}
Or to write it in a shorter way using LINQ:
var results = Enum.GetValues(typeof(MyEnum))
.OfType<MyEnum>()
.Select(x => new { Value = x, IsPowerOfTwo = (x != 0) && ((x & (x - 1)) == 0) } )
.Where(x => !x.IsPowerOfTwo && x.Value.HasFlag(myEnumData))
.Select(x => x.Value.ToString());
This will give an IEnumerable<string> containing the results. In case that myEnumData has a value of MyEnum.Apple the result will contain just the value "Fruit".

as #Henk Holterman has suggested, you need first to assign values to the enum.
All values should be a power of 2 (and avoid using 0, except for the special case of "None")
It should look something like this:
MyEnum eVal= (MyEnum ) Enum.Parse( typeof(MyEnum), data, true );
if((MyEnum.Fruit & eVal) != 0) MessageBox.Show("Fruit");
You might want to read more about bitwise and boolean algebra.

Related

Convert a flagged enum to another one

I have a general enum, let's say G that has some flagged values (One = 0 / Two = 1 / Three = 2 / Four = 4 / Five = 8, and so on).
I then have another enum (let's say B) that "extends" G with this kind of pattern : One = G.One / Two = G.Two / Three = G.Three / Four = G.Four (and that's all, no Five in this one).
I finally have have a last enum (let's say C) that also "extends" G with the same pattern type but other values : Three = G.Three / Four = G.Four / Five = G.Five (no One and Two in this one).
I'd like to find a generic function to convert B into C or C into B.
For example, if I have "A valsAsA = A.One | A.Three | A.Four", I'd like a function like this : "B valsAsB = convert(valsAsA);" that would gives me "B.Three | A.Four".
This should be really generic because I have not only A and B enums, but also C, D, E... with different possible enum values, but always values from the generic enum.
Is it possible without checking all possibilities and adapting the function each time I add a new enum ?
An example:
public enum General : int
{
One = 0,
Two = 1,
Three = 2,
Four = 4,
Five = 8
}
public enum A : int
{
One = General.One,
Two = General.Two,
Three = General.Three,
Four = General.Four,
}
public enum B : int
{
Three = General.Three,
Four = General.Four,
Five = General.Five
}
public enum C : int
{
One = General.One,
Three = General.Three,
Five = General.Five
}
public class Test
{
public void testConvert()
{
A valAsA = A.One | A.Three | A.Four;
B valAsB = convertFct(valAsA); // Should give me "B.Three | B.Four"
C valAsC = convertFct(valAsA); // Should give me "C.One | C.Three"
}
}
I tested that :
A valAsA = A.One | A.Three | A.Four;
C valAsC = (C)valAsA;
C valAsCReal = C.One | C.Three; // expected result
with no luck.. valAsC = 6 while valAsCReal = 2...
Thank you very much
Doing this with generics is a little tricky because it is not possible to set up a type constraint that allows enumerations in general (see this question). The best you can do is constraint to struct, IConvertible and do a runtime check, as I do in this example.
If you can cope with that part of the ugliness, the rest is fairly simple:
First, write two methods to convert to and from a General. Since your enums are bit masks, the "conversion" is actually just a binary and operation against the sum of all possible values, which you can obtain using GetValues.
Once you have performed the and operation, you can return an enum of the appropriate type by converting the integer using Enum.ToObject().
static public class ExtensionMethods
{
static public General ToGeneral<T>(this T input) where T : struct, IConvertible
{
if (!typeof(T).IsEnum) throw new ArgumentException("Input must be an enum.");
return (General)((int)(object)input & Enum.GetValues(typeof(General)).Cast<int>().Sum());
}
static public T ToEnum<T>(this General input)
{
if (!typeof(T).IsEnum) throw new ArgumentException("Output type must be an enum.");
return (T)Enum.ToObject(typeof(T), (int)input & Enum.GetValues(typeof(T)).Cast<int>().Sum());
}
}
Once those are written, conversion to and from any enum is easy:
static public TOut Convert<TIn,TOut>(TIn input) where TIn : struct, IConvertible where TOut: struct, IConvertible
{
var general = input.ToGeneral();
return general.ToEnum<TOut>();
}
Test code:
public static void Main()
{
A valAsA = A.One | A.Three | A.Four;
B valAsB = Convert<A, B>(valAsA); // Should give me "B.Three | B.Four"
C valAsC = Convert<A, C>(valAsA); // Should give me "C.One | C.Three"
Console.WriteLine("{0} should equal {1}", valAsB, (B.Three | B.Four));
Console.WriteLine("{0} should equal {1}", valAsC, (C.One | C.Three));
}
Output:
6 should equal 6
Three should equal Three
See the code in action at DotNetFiddle
Damn !!! I could create this incredible function that answer to my question but please... tell me that there is something more elegant... xD
private TRet ConvertIt<TRet, TOrig>(TOrig values) where TOrig : struct, IConvertible where TRet : struct, IConvertible
{
if (!typeof(TOrig).IsEnum ||
!typeof(TRet).IsEnum ||
!typeof(int).IsAssignableFrom(typeof(TOrig)) ||
!typeof(int).IsAssignableFrom(typeof(TRet)))
{
throw new ArgumentException("TOrig and TRet must be an enumerated type extending integer");
}
bool retEnumHasZero = false;
foreach (var flag in Enum.GetValues(typeof(TRet)))
{
if ((int)flag == 0)
{
retEnumHasZero = true;
break;
}
}
if (!retEnumHasZero)
{
throw new ArgumentException("TRet enum must have the 0 flag");
}
Dictionary<int, Enum> valsOrig = new Dictionary<int, Enum>();
foreach (var flag in Enum.GetValues(typeof(TOrig)))
{
valsOrig.Add((int)flag, (Enum)flag);
}
object valuesAsObject = values;
var valuesAsEnum = (Enum)valuesAsObject;
int returnedValue = 0;
foreach (var flag in Enum.GetValues(typeof(TRet)))
{
int flagAsInt = (int)flag;
if (valsOrig.ContainsKey(flagAsInt) && valuesAsEnum.HasFlag(valsOrig[flagAsInt]))
{
returnedValue |= flagAsInt;
}
}
return (TRet)Enum.ToObject(typeof(TRet), returnedValue);
}
Using the function :
A valAsA = A.One | A.Two | A.Three | A.Four;
C valAsC = ConvertIt<C, A>(valAsA);
Edit : This implementation looks better :
private T ConvertIt<T>(Enum values) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Type to return must be an enumerated type");
}
if (!Enum.IsDefined(typeof(T), 0))
{
throw new ArgumentException("Type to return enum must have the 0 flag");
}
int returnedValue = 0;
foreach (var flag in Enum.GetValues(values.GetType()))
{
int flagAsInt = (int)flag;
if (values.HasFlag((Enum)flag) && Enum.IsDefined(typeof(T), flagAsInt))
{
returnedValue |= flagAsInt;
}
}
return (T)Enum.ToObject(typeof(T), returnedValue);
}
Using the function :
A valAsA = A.One | A.Two | A.Three | A.Four;
C valAsC = ConvertIt<C>(valAsA);
Finally, with the help of John Wu, here is the final function =>
private T ConvertIt<T>(Enum input) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Type to return must be an enumerated type");
}
return (T)Enum.ToObject(typeof(T), (int)(object)input & Enum.GetValues(typeof(T)).Cast<int>().Sum());
}

How do you test an enum flag combination?

Let’s say I have an enum flag:
[Flags]
public enum ColorType
{
None = 0,
Red = 1 << 0,
White = 1<<1,
Yellow = 1 << 2,
Blue = 1 << 3,
All = Red | White | Yellow | Blue
}
I have the below function, which parameter is a combination of flag, such as DoSomething( ColorType.Blue | ColorType.Yellow ).
public void DoSomethingr(ColorType theColorTypes)
{
if (theColorTypes.HasFlag(All)) Foo1();
if (theColorTypes.HasFlag(White) && theColorTypes.HasFlag(Red) ) Foo2();
if (!theColorTypes.HasFlag(Blue)) Foo3();
. . .
}
Is there an easy way to test all of possible flag bitwise combination?
[Test]
public void Test1(ColorType.Red | ColorType.Yellow | ColorType.White)
[Test]
public void Test1(ColorType.Red | ColorType.Yellow | ColorType.white | ColorType.Blue)
Thanks
Loop over all the possible values and put it in a TestCaseSource to generate a different test for each enumeration value:
public IEnumerable<ColorType> TestCaseSource
{
get
{
int start = (int)ColorType.None;
int count = (int)ColorType.All - start + 1;
return Enumerable.Range(start, count).Select(i => (ColorType)i);
}
}
[TestCaseSource("TestCaseSource")]
public void Test1(ColorType colorType)
{
// whatever your test is
}
Just my two cents and this could probably be improved to accept 'other' value types as well, but as an alternative when you like extension methods:
public static class EnumExtensions
{
public static bool HasFlags<TEnum>(this TEnum #enum,
TEnum flag,
params TEnum[] flags)
where TEnum : struct
{
var type = typeof(TEnum);
if (!type.IsEnum)
throw new ArgumentException("#enum is not an Enum");
var hasFlagsMethod = type.GetMethod("HasFlag");
var hasFlag = new Func<TEnum, bool>(e =>
{
return (bool)hasFlagsMethod.Invoke(#enum, new object[] { e });
});
// test the first flag argument
if (!hasFlag(flag))
return false;
// test the params flags argument
foreach (var flagValue in flags)
{
if (!hasFlag(flagValue))
return false;
}
return true;
}
}
[Flags]
public enum ColorType
{
None = 0,
Red = 1 << 0,
White = 1 << 1,
Yellow = 1 << 2,
Blue = 1 << 3,
All = Red | White | Yellow | Blue
}
Call it like this:
class Program
{
static void Main(string[] args)
{
var color = ColorType.Red;
Console.WriteLine(color.HasFlags(ColorType.Red)); // true;
Console.WriteLine(color.HasFlags(ColorType.Red, ColorType.Blue)); // false;
color = ColorType.All;
Console.WriteLine(color.HasFlags(ColorType.Red, ColorType.Blue)); // true;
Console.ReadLine();
}
}

Loop through bitwise enum values which have just a single bit field

I have multiple flags enums defined in code similar to the following
[Flags]
public enum Colors
{
None = 0,
Red = 1,
Green = 2,
Blue = 4,
Purple = Red | Blue,
Brown = Red | Green,
}
The following code produces the following output
Colors color1 = Colors.Red | Colors.Blue;
Colors color2 = Colors.Purple;
string s1 = color1.ToString(); // Sets s1 to "Purple"
string s2 = color2.ToString(); // Sets s2 to "Purple"
I want a method that outputs the individual bits of a bitwise enum, even if a matching combination is defined.
private void Foo()
{
Colors color1 = Colors.Red | Colors.Blue;
Colors color2 = Colors.Purple;
string s1 = CreateColumnString(color1); // Sets s1 to "Red|Blue"
string s2 = CreateColumnString(color2); // Sets s2 to "Red|Blue"
}
I thought I could loop through all the values of an enum and check if the value is a power of two. But I can't figure out how to get the underlying value of the Enum argument.
private string CreateColumnString(object value)
{
//is this an enum with Flags attribute?
if (value is Enum && value.GetType().GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
{
Enum e = (Enum)value;
//Get a list of Enum values set in this flags enum
IEnumerable<Enum> setValues =
Enum.GetValues(value.GetType())
.Cast<Enum>()
.Where(eachEnum => IsPowerOfTwo(eachEnum) && value.HasFlag(eachEnum));
return string.Join("|", setValues);
}
else
{
return value != null ? value.ToString() : string.Empty;
}
return str;
}
private static bool IsPowerOfTwo(Enum e)
{
int x = (int)e; //ERROR cannot convert type 'System.Enum' to 'ulong'
return (x != 0) && ((x & (x - 1)) == 0);
}
There may be better ways of doing this, but this should do what you are looking for:
private static string AsString<T>(this T values)
{
Enum v = (Enum)Convert.ChangeType(values, typeof(Enum));
Array array = Enum.GetValues(typeof(T));
IEnumerable<Enum> setFlags = array
.Cast<Enum>()
.Where(c => v.HasFlag(c) && IsDistinctValue(c));
return values.Equals(default(T))
? default(T).ToString()
: string.Join("|", setFlags.Where(c => Convert.ToInt32(c) != 0).Select(c => c.ToString()));
}
private static bool IsDistinctValue(Enum value)
{
int current = Convert.ToInt32(value) >> 1;
while (current > 0)
{
if ((Convert.ToInt32(value) & current) != 0)
{
return false;
}
current >>= 1;
}
return true;
}
It will essentially list the values for the set flags, except those that "contain" other flags. It figures this out by taking the value that is being tested, decrementing it towards zero and check whether the original value has that decremented value set as a flag. Finally, it will remove the "None" value, unless no flag is set.
Use it like so:
Colors c = Colors.Purple;
Console.WriteLine(c.AsString());
Here's another approach. I figure the more options you have, the better :)
public static class EnumHelpers
{
public static string ToStringExtended<T>(this Enum e)
{
if (!(e.GetType().GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0))
return e.ToString();
List<string> eNames = new List<string>();
foreach (T fish in Enum.GetValues(typeof(T)))
{
Enum num = fish as Enum;
if (e.HasFlag(num) && Convert.ToInt32(fish) != 0 && Convert.ToInt32(fish) != Convert.ToInt32(e))
eNames.Add(fish.ToString());
}
return eNames.Count > 1 ? String.Join("|", eNames.ToArray()) : e.ToString();
}
}
The usage is almost identical to what Fredirk proposed:
Colors c = Colors.Purple;
Console.WriteLine(c.ToStringExtended<Colors>());
// Output : Red|Blue
You can use the HasFlag method:
.Where(e.HasFlag)
However, I think that your Enum.GetValues call will also get the multi-bit values that your enum type names.
EDIT:
Here's another approach that you might get to work:
if (Enum.GetUnderlyingType(e.GetType()) != typeof(int))
throw new NotImplementedException();
var list = new List<Enum>();
for (int i = 1; i != 0; i <<= 1)
{
var eachEnum = (Enum)(Enum.ToObject(e.GetType(), i));
if (e.HasFlag(eachEnum))
list.Add(eachEnum);
}
return string.Join(" | ", list);
An answer in 4 lines of code not counting the method signature.
private static string CreateColumnString(Colors value)
{
// This is how we do it in embedded programming in C
// In C we wouldn't need to convert, but alas in C# we do
// So first ...
var num = Convert.ToByte(value);
// ToUint16 would work as well, but ToByte makes your intentions clearer
// Then bitwise '& 'every bit position you care about to compose your string
// For example: 0b0011 & 0b1111 = 0b0011 (3 AND 15 = 3)
var s = (num & 1) > 0 ? "Red" : "";
s = (num & 2) > 0 ? s + "|Green": s;
return (num & 2) > 0 ? s + "|Blue" : s;
}

System.Enum combinations with Flags

Consider the following enumeration:
[System.Flags]
public enum EnumType: int
{
None = 0,
Black = 2,
White = 4,
Both = Black | White,
Either = ???, // How would you do this?
}
Currently, I have written an extension method:
public static bool IsEither (this EnumType type)
{
return
(
((type & EnumType.Major) == EnumType.Major)
|| ((type & EnumType.Minor) == EnumType.Minor)
);
}
Is there a more elegant way to achieve this?
UPDATE: As evident from the answers, EnumType.Either has no place inside the enum itself.
With flags enums, an "any of" check can be generalised to (value & mask) != 0, so this is:
public static bool IsEither (this EnumType type)
{
return (type & EnumType.Both) != 0;
}
assuming you fix the fact that:
Both = Black | White
(as Black & White is an error, this is zero)
For completeness, an "all of" check can be generalised to (value & mask) == mask.
Why not simply:
public enum EnumType
{
// Stuff
Either = Black | White
}
How about:
[System.Flags]
public enum EnumType: int
{
None = 0,
Black = 1,
White = 2,
Both = Black | White,
Either = None | Both
}

How do I decode bits in order to get the original values?

Assuming I have the following enum
[Flags]
enum Options
{
Option1 = 1 << 0,
Option2 = 1 << 1,
Option3 = 1 << 2
}
And I were to set a variable as follows
var options = 0;
options |= Options.Option1;
options |= Options.Option3;
// now options should equal Option1 + Option3
// I then store that single value in the database
myDatabase.Options.Submit(options);
How do I then parse "Options" in order to get the original values back?
public List<Options> ParseOptions(Options options)
{
// Not sure how to parse the options.
}
You could use the Enum.HasFlag() method to see if a particular flag is set. Just go through all the individual values testing if it is set.
var value = Options.Option1 | Options.Option3;
foreach (Options flag in Enum.GetValues(typeof(Options)))
{
if (value.HasFlag(flag))
{
// do something with the flag
}
}
Note that the HasFlag() method was added to .NET 4. It is however logically equivalent to this:
public static bool HasFlag(this Enum value, Enum flag)
{
return (value & flag) == flag;
}
Something like:
public List<Options> ParseOptions(Options options)
{
var list = new List<Options>();
foreach(MyEnum val in Enum.GetValues(typeof(myEnum)))
{
if ((val & options) == val)
List.Add(val);
}
return list;
}
(not verified in Visual Studio)

Categories