Why isn't this code unreachable?

Solution 1:

Static analysis can only do so much, and it will only mark code as unreachable if it can prove that a value cannot be changed. In your code, what happens inside Bar is out of the scope of the method flow and can't be statically reasoned about. What if Bar's constructor launches a thread that sets the value of type back to B? The compiler can't know about it, because, again, the internals of Bar aren't scoped to the method.

If your code was checking the value of a local variable, then the compiler could know if there was no way for it to change. But that's not the case here.

Solution 2:

The C# specification says,

The first embedded statement of an if statement is reachable if the if statement is reachable and the boolean expression does not have the constant value false.

and, concerning constant expressions,

A constant expression must be the null literal or a value with one of the following types: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, object, string, or any enumeration type.

Only the following constructs are permitted in constant expressions:

  • Literals (including the null literal).
  • References to const members of class and struct types.
  • References to members of enumeration types.
  • References to const parameters or local variables
  • Parenthesized sub-expressions, which are themselves constant expressions.
  • Cast expressions, provided the target type is one of the types listed above. checked and unchecked expressions
  • Default value expressions
  • The predefined +, , !, and ~ unary operators.
  • The predefined +, , *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above.
  • The ?: conditional operator.

Member access expressions are not in this list, so the boolean expression is not constant. Thus the body of the if block is reachable.

Solution 3:

Because no such guarantee can be made at compile time. Consider this alternative Bar class

class Bar
{
   Random random = new Random();
   Array Foos = Enum.GetValues(typeof(Foo));

    private Foo _type;
    public Foo type
    {
        get { return _type; }
        set
        {
            _type = (Foo)Foos.GetValue(random.Next(3));
        }
    }
}

Please note that "reachable" is defined at function level. It is not allowed to reach outside the function that is being tested even when it is safe to do so.