Just an addendum to the answer:
The reason is I beleive, that it'll only do static checking. in the first case if(false) it'll see that that's unreachable code by a simple pattern check, so it'll not compile it in (should give a warning too).
For the second case, because F is a constant and it know it never changes,when doing static checking it can just do substitution. [F->false]<< body >>. and that would give the same code as the first one.
The last one is tricky. Since it's infeasible to know that 100% using static checking only what the value of F is. C# like all imperative languages have side effects.
imagine if you rewrite the code slightly
bool F = false;
foo(ref F);
if(F) {
// some code - is this compiled?
}
The problem here is, it doesn't know what foo does to F. in order to find out, it would have to trace (and possibly evaluate) the function, now imagine a very large programs with alot of these patterns, after all, If statements are used alot, trying to find the runtime value of F for all these statements would be very slow and time consuming and sometimes not even possible.