Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does if((attributes & FileAttributes.Hidden) == FileAttributes.Hidden) { } work?

Tags:

c#

.net

bitmask

On this page, I see the following code:

if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden)

But I don't understand why it is the way it is.

Why attributes & FileAttributes.Hidden)? What does the singular check on attributes actually do? Does it check if it's not null? I have a feeling I know, but it seems weird. Random and weird.

like image 492
forloop Avatar asked Sep 07 '15 09:09

forloop


2 Answers

It's simple boolean logic. The == operator only returns true if both sides have the exact same value. So you have to mask the attributes value with the flag you want to compare against. Consider those two examples (values are made up):

true:

  0010001 // attributes
& 0000001 // FileAttributes.Hidden
  -------
= 0000001 // FileAttributes.Hidden

false:

  0011000 // attributes
& 0000001 // FileAttributes.Hidden
  -------
= 0000000 // FileAttributes.None
like image 69
m0sa Avatar answered Sep 30 '22 12:09

m0sa


attributes is of FileAttributes type. This type is an enum, a value type. It is not FileAttributes? (Nullable<FileAttributes>), so it simply cannot be null.

Every enum consists of a list of named values, but each of them is mappable/convertible to some integer (int) values. In many places C# allows you to "exploit" that conversion and (somewhat) treat enum values as if they were ints, but still they are not.

For example, the & operator performs what you'd expect - it performs binary AND. This way, if the enum value, converted to integer, has relevant bit(s) set, you will get some nonzero result.

In a "good old way" of checking if some flags/bits are present in some status value. You may often see expression like foo & FLAG != 0 which checks if the flag is set, or foo & (FLAG|BLAG) != 0 that checks if any of those two is set. This is a little flawed/dangerous because if someone changes FLAG to have more than one bit, then such expressions would check if ANY bit is set, not if the whole such "multi-bit flag" is set. That's why you may also often see foo & FLAG == FLAG that applies the bitmask and checks if the result IS the bitmask, so it checks if all bits of mask are set.

Here, in your case it's just that. Since in that expression you are ANDing and COMPARING with the same mask, you are effectively checking if ALL bits of the mask are set. But that's superfluous as the FileAttributes is clearly marked as [Flags], the Hidden value has just one bit, so != 0 would be enough.

However, in such cases (checking flags, not fancy bitwise masks) you may try to use Enum.HasFlag method, most people will advise you to use it, since it's designed to such cases ;)

This however is not always the best pick. Please see:

  • http://www.codeproject.com/Tips/441086/NETs-Enum-HasFlag-and-performance-costs
  • http://www.dotnetbitsandpieces.com/?p=11

..but I would be suprised if that performance cost would be an issue to you. Optimizing to this point is very rarely needed.

like image 31
quetzalcoatl Avatar answered Sep 30 '22 11:09

quetzalcoatl