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)
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 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.
I have this sample code:
DirectoryEntry _entry = new DirectoryEntry(
connectionString,
this.userPrinicipalName,
this.password,
AuthenticationTypes.SecureSocketsLayer & AuthenticationTypes.Encryption);
How come I am allowed to make the amp in the last parameter? I am use to java where I have never seen this kind of witchcraft before AND I am new to C# - So can anyone tell me what it is and how I am allowed to do it?
Thanks in advance
Those are probably integers, so you are just doing an binary and (&) of their values.
If you have 1 and 2 the result would be 0 01 & 10 = 00.
Nobody else has pointed this out, but
AuthenticationTypes.SecureSocketsLayer & AuthenticationTypes.Encryption
is a bit weird because SecureSocketsLayer and Encryption are both 2.
So you might as well just put one or the other, not both...
If they were different and you did want to combine them, you should use the OR operator, |, not the AND operator, &.
In this page Authentication Types. It says "This enumeration has a FlagsAttribute attribute that allows a bitwise combination of its member values." Meaning that each attribute has its own bit, so the bits can be combined to have multiple attributes.
This is most likely an enum that has the [Flags] attribute on it. This attribute allows bitwise operators to be used on the enum.
AuthenticationTypes has a FlagsAttribute. Therefore you are able to combine different enumerated values into a composite enum value through for example bitwise OR operations.
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.
I am building a fun little app to determine if I should bike to work.
I would like to test to see if it is either Raining or Thunderstorm(ing).
public enum WeatherType : byte
{ Sunny = 0, Cloudy = 1, Thunderstorm = 2, Raining = 4, Snowing = 8, MostlyCloudy = 16 }
I was thinking I could do something like:
WeatherType _badWeatherTypes = WeatherType.Thunderstorm | WeatherType.Raining;
if(currentWeather.Type == _badWeatherTypes)
{
return false;//don't bike
}
but this doesn't work because _badWeatherTypes is a combination of both types. I would like to keep them separated out because this is supposed to be a learning experience and having it separate may be useful in other situations (IE, Invoice not paid reason's etc...).
I would also rather not do: (this would remove the ability to be configured for multiple people)
if(WeatherType.Thunderstorm)
{
return false; //don't bike
}
etc...
Your current code will say whether it's exactly "raining and thundery". To find out whether it's "raining and thundery and possibly something else" you need:
if ((currentWeather.Type & _badWeatherTypes) == _badWeatherTypes)
To find out whether it's "raining or thundery, and possibly something else" you need:
if ((currentWeather.Type & _badWeatherTypes) != 0)
EDIT (for completeness):
It would be good to use the FlagsAttribute, i.e. decorate the type with [Flags]. This is not necessary for the sake of this bitwise logic, but affects how ToString() behaves. The C# compiler ignores this attribute (at least at the moment; the C# 3.0 spec doesn't mention it) but it's generally a good idea for enums which are effectively flags, and it documents the intended use of the type. At the same time, the convention is that when you use flags, you pluralise the enum name - so you'd change it to WeatherTypes (because any actual value is effectively 0 or more weather types).
It would also be worth thinking about what "Sunny" really means. It's currently got a value of 0, which means it's the absence of everything else; you couldn't have it sunny and raining at the same time (which is physically possible, of course). Please don't write code to prohibit rainbows! ;) On the other hand, if in your real use case you genuinely want a value which means "the absence of all other values" then you're fine.
I'm not sure that it should be a flag - I think that you should have an range input for:
Temperature
How much it's raining
Wind strength
any other input you fancy (e.g. thunderstorm)
you can then use an algorithm to determine if the conditions are sufficiently good.
I think you should also have an input for how likely the weather is to remain the same for cycling home. The criteria may be different - you can shower and change more easliy when you get home.
If you really want to make it interesting, collect the input data from a weather service api, and evaulate the decision each day - Yes, I should have cycled, or no, it was a mistake. Then perhaps you can have the app learn to make better decisions.
Next step is to "socialize" your decision, and see whether other people hear you are making the same decisions.
use the FlagsAttribute. That will allow you to use the enum as a bit mask.
You need to use the [Flags] attribute (check here) on your enum; then you can use bitwise and to check for individual matches.
You should be using the Flags attribute on your enum. Beyond that, you also need to test to see if a particular flag is set by:
(currentWeather.Type & WeatherType.Thunderstorm == WeatherType.Thunderstorm)
This will test if currentWeather.Type has the WeatherType.Thunderstorm flag set.
I wouldn't limit yourself to the bit world. Enums and bitwise operators are, as you found out, not the same thing. If you want to solve this using bitwise operators, I'd stick to just them, i.e. don't bother with enums. However, I'd something like the following:
WeatherType[] badWeatherTypes = new WeatherType[]
{
WeatherType.Thunderstorm,
WeatherType.Raining
};
if (Array.IndexOf(badWeatherTypes, currentWeather.Type) >= 0)
{
return false;
}