If the statement does not work as expected with a combined enumeration value

This is freaky.

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 (don't do what it suggested).

Interestingly, if I debug and scan the code and observe the statement, it always returns TRUE in my debugger, but it cannot enter the block when I go through the code.

Why does the debugger show that the statement is TRUE , but continue as if not? This is similar to what the debugger tells me that there is fiber.

Has anyone ever experienced this?

PS I am using Xamarin studio 5.9.7

+5
source share
2 answers

Too long for a comment:

Actually, the [Flags] attribute does not change the semantics of the enumeration at all, it is most often used by the ToString method to retrieve a series of names, not a number, for a combined value.

Let's say your enum was declared as follows (without the Flags attribute):

 enum TicketStatus { Created = 1, Transferred = 2, Sold = 4 } 

You can still combine different elements and perform any arithmetic that applies to the enumeration of flags:

 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 .

It is also important to note that in TicketStatus.Created | TicketStatus.Transferred TicketStatus.Created | TicketStatus.Transferred you really do a bitwise OR at the base integer value, note how in our example the assigned values ​​are uniquely combined:

 Created : 0001 Transferred: 0010 Sold: 0100 

Therefore, the value 3 can be unambiguously defined as a combination of Created and Transferred . However, if we had this:

 enum TicketStatus { Created = 1, // 0001 Transferred = 2, // 0010 Sold = 3, // 0011 } 

As can be seen from the binary representations, combining values ​​and checking against members is problematic, because the joined members can be ambiguous. for example, what is status here?

 status = TicketStatus.Created | TicketStatus.Transferred; 

Is it Created, Transferred or is it really Sold ? However, the compiler will not complain if you try to do this, which can lead to complex tracking of errors like yours, where some checks do not work as you expect, so you need to make sure that the definition is normal for bitwise mixing and comparison.

In a related note, since your if really checks to see if it has only Created status, regardless of whether it is merged with other members, the best way to check is (.NET> = 4):

 status.HasFlag(TicketStatus.Created) 

or (.NET <4):

 (status & TicketStatus.Created) != 0 

As for why your enum does not work as expected, it is almost certainly because you did not specify an unambiguously bitwise combinable value to your members (usually degree two).

+3
source

Thanks @MarcinJuraszek and @YeldarKurmangaliyev.

It seems that the [Flags] attribute was not set on the enumeration, as I thought. Adding this attribute now causes the enumeration to work in any combination.

Thus, it seems that the absence of this attribute affects the order of the combined enum values.

0
source

Source: https://habr.com/ru/post/1236287/


All Articles