C# and it’s broken scope rules

I just got bit by a real fluke in C#.

I’m sure one of Hejlsbergs soldiers will dig deep into the spec and locate some addendum to a side-paragraph that explains it as perfectly reasonable behaviour, but before you do that, I’d like you to inspect the code and, without running or compiling it, tell me what you would expect would happen:

 public void WeirdCSharp()
   int i=1;
   DateTime dt2 = new DateTime();
     case 0:
       DateTime dt = new DateTime();
       SomeFunction( () => { Debug.Log (dt2); Debug.Log (dt);} );
     case 1:
       SomeFunction( () => { Debug.Log (dt2); } );
 public void SomeFunction(VoidEvent d) { d(); }

I expected this to print out dt2.

Not so. In fact, it will throw a run-time error of enigmatic proportions:

ArgumentException: Value does not fall within the expected range.

Never mind that the error makes about as much sense as tea without biscuits, but it is in fact thrown in case 1 when SomeFunction is called – not because there is anything wrong with this line, but because (I assume) the dt variable from the case above is un-initialized but gets captured in the call block due to the messed up switch-level scope.

You can fix it by introducing local scope in the case (add curly brackets). Ironically, I’ve made a general habit of this because C# has weird scope rules in switch statements, but missed it this once.

So yes, there’s a simple workaround, but obviously, C# should never have had scope at the switch level – it made some amount of sense in C when you could fall through from one case to the next, but since C# does not allow this, there is absolutely no point in maintaining this arcane design.

And thus, no reason for this issue to exist.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s