Can you give an example of how unreachable code can still change runtime method behavior?
I stumbled upon one by accident.
This is just some funny observation that came up when I created some hand-written mocks returning an IEnumerable
with yield
.
At some point I ended up with a (mock) method like this:
IEnumerable<int> GetInts() { throw new Exception(); yield return 1; // this triggers CS0162 Unreachable code detected }
Its purpose was to return an IEnumerable
that throws an exception upon iteration, which it does.
This NUnit test will pass:
TestDelegate callMethod = () => GetInts(); TestDelegate callMethodAndIterate = () => { var integers = GetInts(); foreach (var integer in integers) { } }; Assert.DoesNotThrow(callMethod); Assert.Throws<Exception>(callMethodAndIterate);
Now, what about that CS0162?
If we blindly follow its advice and remove the yield
line, we break the method’s behavior, because without yield
the compiler does not generate a throwing enumerator anymore.
Instead, the method becomes just a normal method that immediately throws an exception when called.
The test above now fails on the first assertion.
This means that in this case unreachable code is necessary for the method to behave correctly.
Not because the code will ever be executed at runtime, but because it triggers the compiler to generate a completely different IL method at compile time.
Funny.