7

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.

RubberDuck
  • 11,933
  • 4
  • 50
  • 95
forloop
  • 147
  • 8
  • 3
    Use Enum.HasFlag instead (https://msdn.microsoft.com/en-us/library/system.enum.hasflag%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396). – Andrei Tătar Sep 07 '15 at 09:27
  • 2
    Read the [FileAttributes](https://msdn.microsoft.com/en-us/library/system.io.fileattributes(v=vs.110).aspx) page as well. It states taht the type has a FlagsAttribute attribute, which means the value is treated as a collection of logical flags, rather than a set of values. This means you use the logical AND (`&`) and OR (`|`) operatotros to check it's flag fields. – Evil Dog Pie Sep 07 '15 at 09:30
  • 1
    See this answer to a similar question. Very well written IMO. http://stackoverflow.com/a/1769814/1260204 – Igor Sep 07 '15 at 09:31
  • 1
    Do be aware that if you use [`HasFlag`](https://msdn.microsoft.com/en-us/library/system.enum.hasflag%28v=vs.110%29.aspx) that [it is slow](http://stackoverflow.com/questions/7368652/what-is-it-that-makes-enum-hasflag-so-slow). – Wai Ha Lee Sep 07 '15 at 09:35

3 Answers3

16

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
m0sa
  • 10,712
  • 4
  • 44
  • 91
4

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:

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

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
3

& is a bitwise and operator.

This operator just performs a bitwise AND to 2 sets of bits.

0 & 0 === 0
1 & 0 === 0
0 & 1 === 0
1 & 1 === 1

Next to the and operator, there also exists an OR (|) and XOR (exclusive OR) (^) operator.

Frederik Gheysels
  • 56,135
  • 11
  • 101
  • 154
  • 1
    ^ is a XOR operator, ~ is a NOT. XOR means "1 if either one but not both bits are 1", NOT means "1 if both bits are 0". – Kevin Sep 07 '15 at 13:06