This is a quirky one.
I have the following code...
foreach (IScanTicket ticket in this) {
if (ticket.Status == TicketStatus.Created || ticket.Status == (TicketStatus.Transfered | TicketStatus.Created))
return ticket;
}
}
When I run this, where the status is Created|Transferred, the if statement seems to fail (not do what it's suppose to).
The interesting thing is that if I debug and step through the code and watch the statement, it always returns TRUE in my debugger, yet it fails to enter the block when I step through the code.
Why would the debugger show that the statement is true, yet continue like it's not? It's like what the debugger is telling me fibs.
Has anyone ever experienced this?
P.S. I'm using Xamarin studio 5.9.7
Too long for a comment:
Actually, the [Flags] attribute does not change an enum's semantics at all, it's most popularly used by the ToString method to emit a series of names rather than a number for a combined value.
Let's say your enum was declared like this (without the Flags attribute):
enum TicketStatus
{
Created = 1,
Transferred = 2,
Sold = 4
}
You could still combine different members and do any arithmetic that applies to a Flags enum:
TicketStatus status = TicketStatus.Created | TicketStatus.Transferred;
However, the following will print 3:
Console.WriteLine(status);
But if you add the [Flags] attribute, it will print Created, Transferred.
Also, it's important to note that by TicketStatus.Created | TicketStatus.Transferred you're really doing a bitwise OR on the underlying integer value, notice how in our example that the assigned values are unambiguously combinable:
Created : 0001
Transferred: 0010
Sold: 0100
Therefore a value of 3 can be unambiguously determined as a combination of Created and Transferred. However if we had this:
enum TicketStatus
{
Created = 1, // 0001
Transferred = 2, // 0010
Sold = 3, // 0011
}
As it is obvious by the binary representations, combining values and checking against members is problematic as combined members could be ambiguous. e.g. what is status here?
status = TicketStatus.Created | TicketStatus.Transferred;
Is it Created, Transferred or is it really Sold? However, the compiler won't complain if you try to do it, which could lead to hard to track down bugs like yours, where some check is not working as you expect it to, so it's on you to ensure the definition is sane for bitwise mixing and comparing.
On a related note, since your if statement is really only checking if the ticket has a Created status, regardless of being combined with other members, here's a better way to check for that (.NET >= 4):
status.HasFlag(TicketStatus.Created)
or (.NET <4):
(status & TicketStatus.Created) != 0
As to why your enum did not work as expected, it is almost certainly because you did not explicitly specify unambigously bitwise combinable values to its members (typically powers of two).
Thanks to #MarcinJuraszek and #YeldarKurmangaliyev.
Seems the [Flags] attribute wasn't set on the enum as I originally thought. Adding this attribute now makes the enum work in either combination.
So it seems that not having this attribute effects the order of joined enum values.
Related
I am trying to find a specific Enum from a list of objects. Here is the code:
foreach (IEquipment eq in EntityEquipmentList)
{
if (eq.capability == capabilityEnum.Jam)
{
Console.WriteLine(eq.ToString())
}
}
Just to be clear, EntityEquipmentList is a List of IEquipment objects and I am trying to find the one that has "Jam" as it's capability. As you can see in the "if" statement, I want the capability of "Jam".
Enum in question:
Radar = 1
Jam = 2
Radio = 4
LowFreq = 8
HighFreq = 16
And to be clear, I am 100% certain that there is a piece of Equipment in the list with the Capability of Jam.
Note that the values in your capabilities enum are "powers of two" (1, 2, 4, 8, ... instead of 1, 2, 3, 4, ...). This is usually done for flag enums, where an enum value can be a combination of different defined values. For example, an equipment could have the capability of Jammer as well as Radar.
Well, now Jammer + Radar (or, to be precise: Jammer | Radar, using bitwise OR) is not equal to Jammer, which is why your comparison fails. You can fix this by using HasFlag instead of Equals:
if (equipmentCapability.HasFlag(CapabilityEnum.Jammer)) { ... }
In addition, you should add the Flags attribute to your enum. This
documents the fact that these enum values can be combined, and also
causes equipmentCapability.ToString() to output Jammer, Radar instead of the numerical value.
This question already has answers here:
if GetFields() doesn't guarantee order, how does LayoutKind.Sequential work
(3 answers)
Closed 2 years ago.
Say you have an enum like the following:
namespace MyApp
{
public enum Colors
{
Red = 0,
Blue = 1,
Green = 2,
Yellow = 3
}
}
You want to retrieve the enum as an array, so you use this function to get all the information and then send it back to the front end.
Type.GetFields(BindingFlags.Public | BindingFlags.Static)
where type is my enum Colors. Now in my local environment, I get the values in the ordered they're declared. Every time I refresh the page the enum array is ordered the same, no changes.
However, my app is already deployed in another environment, and in this server is retrieving the array in different ordered every time. This is causing a front end error but I can't fix something I can't actually see on my local environment.
Does the Type.GetFields function has a different behavior regarding, I don't know, the .NET Framework version I'm using to run the project? That's the only thing I can think of at the moment.
I need to reproduce this in my environments before making this change.
From the Type.GetFields() documentation:
Remarks
The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which fields are returned, because that order varies.
Use Enum.GetNames() instead of Type.GetFields().
The Remarks for that method say:
The elements of the return value array are sorted by the binary values of the enumerated constants (that is, by their unsigned magnitude).
It's specified in the documentation, so it should be consistent.
In the following code block there are a few bitwise OR's. I've never used them before so I was trying to understand what the code block meant.
Document doc = new Document("CleanupOptions.docx");
doc.MailMerge.CleanupOptions = MailMergeCleanupOptions.RemoveUnusedRegions |
MailMergeCleanupOptions.RemoveUnusedFields |
MailMergeCleanupOptions.RemoveContainingFields;
doc.MailMerge.ExecuteWithRegions(dataSet);
So in that block above, if I used doc.MailMerge.CleanupOptions, how would I pick any of the statements that the CleanupOptions are equal to? Or are they all combined?
They are all combined. An enum can be marked with the [FlagsAttribute] which allows combination of values:
https://msdn.microsoft.com/en-us/library/system.flagsattribute(v=vs.110).aspx
The MailMergeCleanupOptions is an enum with the FlagsAttribute specified. This allows you to do bit-wise ors to join the values into a collection. Normally the values are powers of two or a combination of flags.
I have some code in c# which needs to increment a number by 1 if a certain boolean value is true, but else it needs to say the same. The only method i've found using the Immediate window in VS 2012 is by + Convert.ToInt32(boolean).
Am I missing something obvious in here somewhere? I thought since a boolean is basically true (1) or false(0) (let's forget about FileNotFound), it would be easier to coerce a boolean to an Int value.
edit:
false is 0, not 1
edit2: my original edit got swallowed up. I'm currently doing a nullcheck on the number (the number is a nullable int field from a Dynamics CRM 2011 entity). Is it possible to keep that nullcheck?
I don't think that adding boolean flag to some value is very readable solution. Basically you want to increment (i.e. add 1) value if flag is true. So, simple if check will clearly describe your intent add do the job:
if (flag) value++;
UPDATE: According to your edit, you want to do two things:
Set default value to your nullable value
Increment value if some condition is true.
To make your code clear, I would not try to put both things in one line. Make your intent explicit:
value = value ?? 0; // 1
if (flag) // 2
value++;
The simple solution would be like so:
val += flag ? 1 : 0;
The fact is that a .NET boolean is simply a completely different type from integer (unlike in, say, C++, where it's a "renamed" integer). The fact, that it is actually implemented using an integer value, is implementation detail and not to be relied upon. In fact, you can do a lot of strange things when you mess with the actual value of the boolean (for example, using direct memory manipulation or overlapping structure fields) - the consistency goes away.
So, don't work with the "actual value of boolean". Simply expect the two possible values, true and false, and work with those.
You can still use the null-check and add the value according to the boolean, like this:
obj.Variable = (obj.Variable ?? 0) + (yourBoolean ? 1 : 0);
//obj is the instance of your object
//Variable is the nullable integer
//yourBoolean is the bool to check against
Object.variable is int variable OR Nullable? If Int varable it's default value is 0, and you can just write like this: Object.variable+=bool?1:0, else can use it: Object.variable=Object.variable??0+bool?1:0
I am reading this article on how to work with AD via C#. Half way through the article, the below code is presented.
The user account properties are checkboxes. Does anyone have any idea what the below line of code will return for a checked checkbox? What if more than 1 checkbox is checked? I'd have thought a bool being returned would be more intuitive?
//Add this to the create account method
int val = (int)newUser.Properties["userAccountControl"].Value;
//newUser is DirectoryEntry object
Why do we do the logical or below? How does it work between an int and the second value (is that a byte?)
newUser.Properties["userAccountControl"].Value = val | 0x80000;
//ADS_UF_TRUSTED_FOR_DELEGATION
I know that sounds very naive...
Thanks
The userAccountControl property contains a two byte value in which each single bit has a significant meaning. If the bit is on, then some option is used - if it's not on, then the option is not present.
This is more compact and more space optimized than having a gazillion of booleans. Also, many "older" Win16 and Win32 API just simply work this way.
The bitwise "AND" operator is used to check for the presence of such a single bit:
if (newUser.Properties["userAccountControl"].Value & 0x400 == 0x400)
in this case, the 0x400 bit is set.
In order to actually set a bit, you use the bitwise "OR" operator:
newUser.Properties["userAccountControl"].Value = val | 0x800
This sets the "0x800" bit.
It's basic bit-wise boolean logic, really. A bit messy, indeed - but .NET has some help to make things a bit easier (check out the BitArray data type, for instance)
userAccountControl is a flag field, that's why they put it into an int.
See http://support.microsoft.com/kb/305144 for more information.
Based on the information that you are giving, I would guess that they are using a flags type system to indicate selected items. Each option has a specific value, and they are added up so you can get back which are selected.
This would be proved by the logical or that is used to see if a specific value is included.