I am after some quick code to help with my logic on bitwise code (my first time doing it)
Basically I have 3 properties each with an ID of 1,2,4
int A = 1
int B = 2
int C = 4
Lets say A and C are checked, this will equal 5 and this value will be saved into the database. Good.
Now I need to work out on the way back what was checked with that value.
So in the example, the value is 5, so how will I know with bitwise logic what properties were checked?
So I am not asking for you to do my work, knowing what I do,
int i = A & C;
// if i == 5, then we know it was A and C checked
But do you need to do that for each possibility?
Thanks in Advance
You can simply check for these conditions:
i & A != 0 // true if A is set in i
i & B != 0 // true if B is set in i
Having said that, bitfields are inappropriate in lots of situations. Especially when you store the resulting value into a database it is usually better to just define some more columns storing each flag.
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 am currently thinking of a way to store checkbox values (true/false) in a database, without using a boolean column for each checkbox. Is there a way to store them in a byte that contains the information for, let's say, six checkboxes?
For example:
* Checkbox 1 to 6 all unchecked would be 00000000
* Checkbox 1 to 6 all checked would be 00111111
* Checkbox 1 checked, rest unchecked would be 00000001
* Checkbox 3 and 4 checked, rest unchecked would be 00001100
* etc.
BEFORE EDIT: "In the end there would be one byte column and for each row a different combination for checkboxes checked/unchecked."
AFTER EDIT: Oh I see I've been unclear. I didn't mean that each possible combination of checkboxes is stored in the table in different rows, like a lookup table. It's more like, the whole table contains information from a user entry in a formular and the checkboxes which were checked by the user are just one element of the form (one column of a db row). Therefore each user entry of the form (a row) CAN contain a different byte in the checkboxes column. But if more users chose the same checkboxes, the byte in their row would look the same of course.
Would this make sense as an alternative to a bunch of boolean columns (one for each checkbox)?
Is there a better way to handle checkbox values in the db?
Is there a way to set each bit of a byte manually in C#? I can't seem to find an explanation on how to do this.
You have to define the enum size for byte, and must have an attrbute FlagAttribute.
Here is the sample code for it:
[Flags]
public enum BitFields : byte
{
CheckBox_01 = 0,
CheckBox_02 = 1 << 0,
CheckBox_02 = 1 << 1,
CheckBox_02 = 1 << 2,
CheckBox_02 = 1 << 3,
CheckBox_02 = 1 << 4,
CheckBox_02 = 1 << 5
}
After you can us if like in C++:
BitFields bits = BitFields.None;
bits |= BitFields.CheckBox_01| BitFields.CheckBox_01;
bits &= ~BitFields.CheckBox_04;
when you write this one byte size enum value, you will get the result what you want.
regrads
You could store a single byte and map different values to checkboxes being checked. IE: 00000000 no button is checked, 00111111 all 6 buttons are checked. This would be a lot of extra work though and doesn't follow good design principles.
If persistent button state is important then I recommend you make a table called buttonstate, storing the state of each button as a row. this will reduce complexity and allow your application to scale better, make the code more manageable, and a whole other host of benefits.
TLDR; don't overcomplicate this, just store the values as booleans. pre-mature optimization is a bad idea.
I don't know why I get 6 as a result when I insert a blank media in my burner. To my understanding there is no 6 in the states of the enumeration of IMAPI_FORMAT2_DATA_MEDIA_STATE.
Here is a link that contain this states and the example that I am based on : MSDN:Checking Media Support.
var state = dataWriter.CurrentMediaStatus;
Debug.WriteLine((int)state); // outputs 6
It is a combination of both of them, basically a bitwise operation is calculated on the two (or more values).
When you make an enum with the attribute Flags then you can do Bitwise operations on it, even though it should work without the attribute
IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK
IMAPI_FORMAT2_DATA_MEDIA_STATE_APPENDABLE
The value of IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK with an 'OR' operation with IMAPI_FORMAT2_DATA_MEDIA_STATE_APPENDABLE will give 6
in C# it would be value = 2 | 4;
To go further if you want to test if the value contains a certain Option you can go ahead and do something like this
if ((value & IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK) == IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK)
{
//IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK is contained
}
You can read more about Bitwise operations here
It's equivalent to a flaggable enum. 6 is 4 + 2, so the state is both
IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK
IMAPI_FORMAT2_DATA_MEDIA_STATE_APPENDABLE
I'm using C# 3.5 for a mobile app on Windows Mobile 6.5 and i've been using this simple code forever but it suddenly stopped working:
//Regroup the issues
ScanIssuesEnum NewIssues = 0;
NewIssues |= Direction1Issues;
NewIssues |= Direction2Issues;
//Remove invalid directions because we don't care about them in bidirectionnal mode
NewIssues ^= ScanIssuesEnum.InvalidDirectionIssue;
return NewIssues;
I checked thoroughly all my types just to make sure i wasn't using another type, everything is based off the same ScanIssuesEnum type and the type is [Flag]'ed as you can see below:
[Flags] public enum ScanIssuesEnum
{
TicketUsedTooSoonIssue = 1,
TicketUsedTooLateIssue = 2,
TicketUsageBustedIssue = 4,
InvalidTripIssue = 8,
InvalidDirectionIssue = 16,
StartStopTooSoonIssue = 32,
StartStopNotFoundIssue = 64,
EndStopTooLateIssue = 128,
EndStopNotFoundIssue = 256,
MultipleUsageSameTripIssue = 512,
MultipleUsageInFewHoursIssue = 1024,
StudentTicketIssue = 2048,
ConnectingTripWithinTimeframeFlag = 4096,
UDESStudentTicketIssue = 8192,
}
In my current problem, i can see EndStopNotFoundIssue in both DirectionIssues, when combined into NewIssues, i get a value that contains two times EndStopNotFoundIssue. I thought it wouldn't really matter until i return the value, maybe it's just a visual IDE bug but no, the problem persists. Even worst, when i hit the line that removes the InvalidDirectionIssue flag, it adds it to the NewIssues...
Am i crazy? ^= is the equivalent of x = x ^ y no? So i should remove the flag, not add it right?
Thanks
Edit #1 - Values of the DirectionIssues
As requested by Wonko the sane, the values of Direction1Issue and Direction2Issue are both EndStopNotFoundIssue or 256.
After the line "NewIssues ^= ScanIssuesEnum.InvalidDirectionIssue;" my NewIssues is composed of "EndStopNotFoundIssue | EndStopNotFoundIssue | InvalidDirectionIssue". And obviously it shouldn't!
Edit #2 - Values of DirectionIssues wrongly read
Ha, the two DirectionIssues had different values, i was just reading them incorrectly. In fact it was EndStopNotFoundIssue and EndStopTooLateIssue. Damn mind not read the whole words hehe. So the OR portion was fine, it was my brain playing tricks on me.
I changed the problematic portion about the InvalidDirectionIssue that i'm trying to XOR out using the "x = x & ~y" form and it works, dunno why it works while the "x ^= y" doesn't but hell! Solution found!
There are several things that might help you.
^ is exclusive-or, so it switches/toggles the bits that you apply, it does not clear them. So if the EndStopNotFoundIssue value is not set, then using ^ will set it, not clear it. If you want to clear a value, use x &= ~y (AND x with the inverted bits of y).
EndStopNotFoundIssue | EndStopNotFoundIssue equals EndStopNotFoundIssue. ORing a value with itself just returns the same value. So you're not telling us something. Are you using a + rather than an | or something? Are the values of the variables you're ORing in really what you think they are? Have you single stepped through the code in your debugger to see what the values are at every stage? You need to post more of your code for us to work out where it's gone wrong.
You're using values that do not appear to have come from your enum (0 and Direction1Issues for example). So we can't read your code to work out what might be going wrong as we have no idea what Direction1Issues is set to. And it's generally a bad idea to mix different types. 0 is an integer, but you are setting it into an enumerated type. Define a constant like None=0 to make your code more readable and more type-safe.
For your constants, try using the style below - it's much easier to see which bit you are setting, know that you are only setting one bit, and be sure that you calculate the next value correctly when you add a new item:
public enum ScanIssuesEnum
{
TicketUsedTooSoonIssue = 1<<0,
TicketUsedTooLateIssue = 1<<1,
TicketUsageBustedIssue = 1<<2,
InvalidTripIssue = 1<<3,
InvalidDirectionIssue = 1<<4,
...
x ^= y is the equivalent of x = x ^ y. That means it toggles the state existence of y in a flags enum. It can be used to set or unset.
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)