I have wrote enum:
[Flags]
public enum BundleOS {
Win32 = 0,
Win64 = 1,
Mac = 2
}
I need parse it from string, and write to string. Sample of string: "Win32|Win64".
Next code returns invalid result:
BundleOS os;
Boolean result = TryParse<BundleOS>("Win32|Win64", out os);
In result variable I got the false value. But I need true, and os value must to have the BundleOS.Win32|BundleOS.Win64 value.
If I do such operation:
String x = (BundleOS.Win32|BundleOS.Win64).ToString();
I need get such value: "Win32|Win64", but I get "Win64".
Is exists a simple solution of these problems?
Your problem is that your performing a bitwise operation and Win32 equals 0.
So Win64 OR Win32 is actually Win64 OR 0 which returns Win64.
You can set your enum like this:
[Flags]
public enum BundleOS
{
Win32 = 1,
Win64 = 2,
Mac = 4
}
On a side note:
I'll also point out a very good question that was asked earlier this week on how to define flag enums.
In addition to the answer given by #Blachshma regarding your particular flags, if you want to take the string form of "Win32|Win64" and turn it into an actual instance of your enum, you've got a bit more work cut out.
First you'll simply need to split() the string by the '"|"' in order to get the individual values.
Then you can use Enum.GetNames() and Enum.GetValues() to get a list of the names and values for elements in your original enum. You can then loop through the split components, and find the matching entry (and its value) from your original enum.
Try this to parse your flags string. I havn't tested but it should get you started:
BundleOS flags = "Win32|Win64"
.Split('|')
.Select(s => (BundleOS)Enum.Parse(typeof(BundleOs), s))
.Aggregate((f, i) => f|i);
In addition to Blachshma's answer, the MSDN documentation for the FlagsAttribute actually explains very succinctly in the "Guidelines for FlagsAttribute and Enum" section:
Define enumeration constants in powers of two, that is, 1, 2, 4, 8,
and so on. This means the individual flags in combined enumeration
constants do not overlap.
Use None as the name of the flag enumerated constant whose value is
zero. You cannot use the None enumerated constant in a bitwise AND
operation to test for a flag because the result is always zero.
However, you can perform a logical, not a bitwise, comparison between
the numeric value and the None enumerated constant to determine
whether any bits in the numeric value are set.
Related
Lets say, for example, I have two implementations, one with bit flags and one with simple enum:
1) bit flags
[Flags]
public enum LettersBitFlags
{
A = 1,
B = 2,
C = 4,
D = 8
}
public static bool IsLetterBBitFlags(LettersBitFlags letters)
{
return (letters & LettersBitFlags.B) != 0;
}
2) simple enum
public enum Letters
{
A,
B,
C,
D
}
public static bool IsLetterBParams(params Letters[] letters)
{
return letters.Any(x => x == Letters.B);
}
They obviously can be used like this:
Console.WriteLine(IsLetterBBitFlags(LettersBitFlags.A | LettersBitFlags.D)); //false
Console.WriteLine(IsLetterBBitFlags(LettersBitFlags.B | LettersBitFlags.C)); //true
Console.WriteLine(IsLetterBParams(Letters.A, Letters.D)); //false
Console.WriteLine(IsLetterBParams(Letters.B, Letters.C)); //true
Is there any practical reason to choose one over the other? As I see, they give the same result, but maybe some performance or anything else should make me use one and did not use the other?
They have different meanings. Flags are characterised by the fact that it's meaningful to OR them together; enums are simply discrete lumps of data, and the fact that they are numerical under the covers is nothing more than an implementation detail.
If you use flags where it's not meaningful to OR two of them together, you will badly mislead anyone who comes to use your data type. Conversely, if you use an enum where you meant a flag, then you'll have to manually capture and name exponentially many enum cases.
Advantages of bit flags:
1) The flags attribute gives you nicer ToString() behaviour than an array of an enum.
2) You can store multiple values in one variable (hence why you don't need an array). This could be important in a memory bound operation.
3) The method Enum.HasFlag exists so you don't actually have to implement your static class.
Disadvantages:
1) You cannot store multiple instances of the same value in the flag - on/off. Your array could have multiple instances of the same value.
2) Any = 0 value will have to be checked separately if you want one.
3) In my option it's not always as clear what you're doing when using bit flags - there's an extra element of knowledge that you need.
The 1st option is good when you represent data in some byte/ int bits, and the data may contain 1 or more of the enum values and then you ca check if data has flag or not.
I have the following enum definition (in C#):
public enum ELogLevel
{
General = -1, // Should only be used in drop-down box in Merlinia Administrator log settings
All = 0, // Should not be used as a level, only as a threshold, effectively same as Trace
Trace = 1,
Debug = 2,
Info = 3,
Warn = 4,
Error = 5,
Fatal = 6,
Off = 7 // Should not be used as a level, only as a threshold
}
Now, when I do an Enum.GetNames() on this type I get a string array with 9 elements as expected, but the order is All, Trace, ... , Off, General, which is not what I was expecting.
Here's the MSDN documentation for Enum.GetNames():
"Remarks: The elements of the return value array are sorted by the
values of the enumerated constants."
What's going on here? I can change my program to take this "functionality" into account, but I'd kind of like to know why .NET is doing what it's doing.
This is a known bug with both GetNames() and GetValues() that was reported here, but ended up getting closed as won't fix:
Yes, this method indeed has a bug where it returns the array of enum values sorted as unsigned-types (-2 is 0xFFFFFFFE and -1 is 0xFFFFFFFF in two's complement, that's why they are showing up at the end of the list) instead of returning values sorted by their signed-types.
Unfortunately, we cannot change the sort order of GetValues because we will break all existing .NET programs that have been written to depend on the current sorting behavior [...]
Looks like you'll have to reorder the values yourself.
Depending on how the sorting occurs, it may be that it is sorting the values as if they were unsigned, in which case, -1 = 0xffffffff, which is of course greater than 7.
I haven't really used bitwise enums before, and I just want to make sure my testing is correct. I am most interested in testing for the values None and All. We receive data from a webservice that utilises this enum to categorise certain pieces of the data. Given that, I am assuming that nether None nor All would ever be combined with any other value.
Given the following bitwise enum definition;
[System.FlagsAttribute()]
public enum TrainingComponentTypes : int
{
None = 0,
AccreditedCourse = 1,
Qualification = 2,
Unit = 4,
SkillSet = 8,
UnitContextualisation = 16,
TrainingPackage = 32,
AccreditedCourseModule = 64,
All = 127,
}
I read the following quote on this MSDN site about FlagAttributes;
Use None as the name of the flag
enumerated constant whose value is
zero. You cannot use the None
enumerated constant in a bitwise AND
operation to test for a flag because
the result is always zero. However,
you can perform a logical, not a
bitwise, comparison between the
numeric value and the None enumerated
constant to determine whether any bits
in the numeric value are set.
Does a logical comparison in this instance refer to a normal equality test for enums?
For example;
TrainingComponentTypes tct = TrainingComponentTypes.None;
if (tct == TrainingComponentTypes.None)
{ ... }
For a bitwise comparison, I am performing the following;
TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification | TrainingComponentTypes.TrainingPackage;
Assert.IsTrue((tct & TrainingComponentTypes.AccreditedCourse) == TrainingComponentTypes.AccreditedCourse, "Expected AccreditedCourse as part the enum");
Assert.IsFalse((tct & TrainingComponentTypes.SkillSet) == TrainingComponentTypes.SkillSet, "Found unexpected SkillSet as part the enum");
Lastly, when testing for all, I have tried both a logical, and bitwise comparison, and they both return the same. Should I be using one over the other here? For example;
TrainingComponentTypes tct = TrainingComponentTypes.All;
Assert.IsTrue((tct & TrainingComponentTypes.All) == TrainingComponentTypes.All, "Expected All as part the enum");
Assert.IsTrue((tct) == TrainingComponentTypes.All, "Expected All as part the enum");
// The follow also pass the assertion for a value of All
Assert.IsTrue((tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification, "Expected Qualification as part the enum");
Assert.IsTrue((tct & TrainingComponentTypes.TrainingPackage) == TrainingComponentTypes.TrainingPackage, "Expected TrainingPackage as part the enum");
So in summary, I'd like to know the following about Bitwise enums;
Is my understanding of a logical
comparison correct given my example
above?
Is the way I am performing
a bitwise comparison correct?
What is the right way to handle the "All"
value (bitwise or logical). I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes. I can't see why we would, but then, you never know?
Am I right in assuming that switch
statements basically shouldn't be
used for bitwise enums (given none
is appears to be a special case and
requires a logical comparison)?
Thanks,
Chris
Short answer: Yes :)
Longer:
1) All operations are performed on the integer value of the flags variable, so you can think about them in terms of this.
2) Yes.
3) Either works. However, it's worth noting that if someone shoves an invalid value into a variable then the == TrainingComponentTypes.All version will fail. For example:
var badValue = (TrainingComponentTypes)128 | TrainingComponentTypes.All;
// now badValue != TrainingComponentTypes.All
// but (badValue & TrainingComponentTypes.All) == TrainingComponentTypes.All
For this part:
I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes.
I'm not sure you fully understand how the enum works under the covers.
The value of All is:
127 = 1111111 (binary)
The other values are:
AccreditedCourse = 0000001
Qualification = 0000010
Unit = 0000100
SkillSet = 0001000
UnitContextualisation = 0010000
TrainingPackage = 0100000
AccreditedCourseModule = 1000000
As you can see, All is simply the bitwise | of all these values together. You can't combine any other TraningComponentTypes with All, because All already includes them! Also, if you combine them all together with | yourself it's exactly the same as using All directly (so, All is simply a convenience when you define it inside an enum).
4) You could use it to check for None or All but not for other values.
It's worth noting that there is a convenience method on Enum that will do these checks for you: Enum.HasFlag.
Is my understanding of a logical comparison correct given my example above?
Yes, logical in this context means the equality and inequality operators.
Is the way I am performing a bitwise comparison correct?
Yes, but there is an easier way: Enum.HasFlag. For example:
tct.HasFlag(TrainingComponentTypes.Qualification)
instead of:
(tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification
What is the right way to handle the "All" value (bitwise or logical). I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes. I can't see why we would, but then, you never know?
I think it is better to define All in the enum itself as the bitwise OR of all its parts. But you'll see people do it both ways.
Am I right in assuming that switch statements basically shouldn't be used for bitwise enums (given none is appears to be a special case and requires a logical comparison)?
No, not at all. Feel free to use them is switch statements. The case values must be constants but they can be expressions and are tested for equality. The compiler will tell you if you do something silly like try to use the same case value twice.
Yes.
Yes
Both logical and bitwise could be used. Usage depends on whether all is all bits set or just the bitwise OR of all the values you've defined.
Yes, but not because of None. A switch compares a single value, whereas a bit field can obviously have multiple values.
As others have noted Enum contains HasFlag().
1 and 2 - yes, however there is a way to make it a little easier to read:
TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification;
Assert.IsTrue(tct.HasFlag(TrainingComponentTypes.AccreditedCourse), "Expected AccreditedCourse as part the enum");
3 - I am not sure if you need All value at all. I would remove it.
4 - Yes, switch statement usually doesn't make sense for Flags enumerations.
"3.What is the right way to handle the "All" value (bitwise or logical). I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes. I can't see why we would, but "
It seems you misunderstand how the bitwise enum values work. 'All' is always combined with other values, in fact it is the combination of all the values. Looking at the binary values for your enum:
None = 0,
AccreditedCourse = 1,
Qualification = 10,
Unit = 100,
SkillSet = 1000,
UnitContextualisation = 10000,
TrainingPackage = 100000,
AccreditedCourseModule = 1000000,
All = 1111111
does that help your understanding?
1&2 look fine
3.
All as you have it defined can't be combined with anything without losing data. If "all" is a real value that you expect to receive from the server you should probably change it to 128.
otherwise it is a convenience value that you can use to test if any value is set... you shouldn't need this unless your flag values are sent as binary data and packed in a byte that may contain other data.
4.
Switch statements could be used but will not work well if/when you have values that have more than one flag, if there are small subsets of valid flag combinations they can still be useful.
In model
as_enum :shifts, { day_shift: 0,
evening_shift: 1,
night_shift: 2,
}, accessor: :bitwise
And in Views
Model.enum_collection(:shifts)
I'm browsing an open source .NET twain wrapper and saw this:
[Flags]
internal enum TwDG : short
{ // DG_.....
Control = 0x0001,
Image = 0x0002,
Audio = 0x0004
}
What exactly does that 'Flag' decorator mean? (Is it called a 'decorator'?)
Also, what does the short mean at the end of the enum declaration?
Thanks!
The Flags Attribute is used to allow and decorate the enumeration for bitwise math operations on enum values.
Doing this allows you to add them together, or other operation items.
The Short part defines it as a Short rather than an integer, detail on this is also in the linked URL
It's an attribute. Although others have said that it is necessary so that you can perform bit flipping operations with the enum, this is not true. You can do this with enums without this attribute.
If you have applied the attribute, you get a different ToString() output on the enum which will pretty-print the combined members of a enum value, e.g. "Blue | Red | Orange", instead of "7".
The "short" keyword means that the type for the enum members will be a 16-bit signed integer.
It means that you give a hint, that this enum will be used for "bitwise or" operations
var flags = TwDG.Control | TwDG. Image;
Console.WriteLine(flags.HasFlag(TwDG.Image)); // true
Console.WriteLine(flags.HasFlag(TwDG.Control)); // true
Console.WriteLine(flags.HasFlag(TwDG.Audio)); // false
More info FlagAttribute (Enum.HasFlag was added in Framework 4.0)
Short is saying, that back-type for this enum is not int (which is default option for enums), but short. Also you can specify long, ushort, or any other integer built-in type.
short is another keyword for System.Int16, a two-byte integer ranging from -32,768 to 32,767. By default, an enum's base type is int; in this case, they're attempting to use a smaller data type to store the enumerator values.
Its the flag attribute, you can read up on it here:
http://msdn.microsoft.com/en-us/library/cc138362.aspx
Lets you treat a set of enums a bit flag set.
the short means that the enum is using short instead of an int as its base type.
as for the flags
http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx
This makes an enumeration a bit-flag.
It means you can combine individual values together.
Like:
TwDG value = TwDG.Control | TwDG.Image | TwDG.Audio;
Which would give it a value of 7.
Individual enumeration values usually have a value of 2^n. But can as well be combined like:
[Flags]
public enum Sides
{
Left = 1,
Right = 2,
Up = 4,
Down = 8,
LeftAndRight = 3,
UpAndDown = 12,
AllSides = 15
}
As for [Flag] - you should look here link text
Short - data time, which used to store enum values.
Flags is an attribute; specifically, System.FlagsAttribute.
It means that the compiler lets you use values of type TwDG as a bit-field, i.e., store as many of them as you want in one value like this:
var control = TwDG.Control;
var allTogether = TwDG.Control | TwDG.Image | TwDG.Audio;
Typically, this is done when some code needs to take different (or optional) actions depending on if one of these flags is set. For example, let's say we want to describe the contents of a video file, which might contain audio and picture. You could write:
var imageAndAudio = TwDG.Image | TwDG.Audio;
var muteImage = TwDG.Image;
Then, if you wanted to check if the file contains an audio track, you would "pick out" the Audio flag like this:
var hasAudio = (myValue & TwDG.Audio) != (TwDG) 0;
I've heard them called decorators before (and it is acceptable to label them as such in the community) but for arguments sake and strictly speaking; it is an attribute. It is used to "mark" the enum as a bit flag type.
Here's the MSDN Reference.
As we know, all enums are compiled as constants, which means you can get unexpected results if you use an enum from a different assembly.
Settings sequential enum numbers explicitly is no help, because if you want to leave room for new values, you have to do basic-linenumber-style spacing, which is naff.
So I wondered about using the hashcode of the Enum value name as string, which is fairly easy to generate a script for.
Is this a good idea? Will I have problems with the negative values that hashcode can return?
EDIT
For those asking why, I quote the linked "corner case":
Given an assembly with:
enum MyEnum
{
Red,
Blue,
}
if you use MyEnum.Red.ToString() in another assembly, and in between times someone has recompiled your enum to:
enum MyEnum
{
Black,
Red,
Blue,
}
at runtime, you will get "Black".
(NB, I am not especially interested in the ToString here, the problem is that if calling code asks for MyEnum.Red, it's actually referencing MyEnum.Black)
Another example to illustrate the problem with explicit sequential numbering:
enum ECountry
{
Afghanistan = 1,
Barbados = 2,
Chile = 3,
...
Zambia = 243,
}
If Giggleswick suddenly declares itself a republic, what do you do?
No, it's not a good idea.
You can't safely recreate a string from it's hash code. You can loop through the names and compare their hash code with the one that you have, but there is still a small risk of a false positive due to hash code collisions. The risk is rather small, but it's still not a reliable method to use.
Just use the name of the enum value if you need to convert from one version of an enum to another. The ToString method gives you the name, and you can use the Enum.Parse method to get the enum value from the string.
Edit:
Using the string value of course requires that you have one occurance of the enum in each assembly so that it's compiled each time. If you are using an enum in a referenced assembly, then you have to give each value a specific numeric representation, otherwise you don't have anything at all that keeps the value consistent from one version to the next.
You won't have problems with negative values. You might have a problem with duplicate values, since the hashcode for a string isn't guaranteed to be unique.
Though, I'd rather just set the values explicitly to 1, 2, 3 and so.
The hashcode of two different string values is not guaranteed to be unique, so that seems like a dangerous option. What is the problem with setting the values explicitly? Unless the numbers have a meaning in your object model then there would seem to be no reason to leave room for new values - just add new options onto the end of the enum.
I'm not sure if I'm misinterpreting things or not, but..
MyEnum.Red.ToString() should yield "Red" not 0. As such an Enum.Parse should be fine with a correct string evaluation. The problem you're describing would be int Foo = (int)MyEnum.Red; Which would be 0; This could cause the inconsistent results described on after a recompile with new elements.
Based on my understanding of the requirements, enum.ToString is persisted, there should be no issue. The issue is when persisting the value or the enum, not the string representation. Therefore, no hashing should be necessary.
Here's an example (pretend we added black)...
class Program
{
static void Main(string[] args)
{
// this is the approach described
string RedToString = MyEnum.Red.ToString();
// We're pretending that red was the zeroth element when we did (int)MyEnum.Red;
int RedToInt = 0;
MyEnum RedFromString = (MyEnum)Enum.Parse(typeof(MyEnum), RedToString);
MyEnum RedFromInt = (MyEnum)RedToInt;
// this is in theory how RedToInt was persisted
int BlackFromInt = (int)MyEnum.Black;
Console.WriteLine("RedToString: " + RedToString); // Red
Console.WriteLine("RedToInt: " + RedToInt); // 0
Console.WriteLine("RedFromString: " + RedFromString); // Red
Console.WriteLine("RedFromInt: " + RedFromInt); // Black
Console.WriteLine("BlackFromInt: " + BlackFromInt); // 0
Console.Read();
}
enum MyEnum
{
Black,
Red,
Blue,
}
}
HTH,
Ben