Thursday 23 February 2012

C# compiler bug - throw in single-line lambda

So I think I may have found a bug with the C# compiler. It's a pretty obscure case which I found when writing a unit test for an error handling module. It seems that the C# compiler won't allow single-line lambda functions to contain the throw keyword. Observe below:

static void Main(string[] args)
{
    ExecuteMethodAndHandleException(() => throw new Exception()); // compiler errors
}

static void ExecuteMethodAndHandleException(Action methodThatWillThrowAnException)
{
    try
    {
        methodThatWillThrowAnException();
    }
    catch (Exception ex)
    {
        // ...
    }
}

The above code generates 5 pre-compile errors, notably Invalid expression term 'throw', and ; expected. However the below works just fine:

ExecuteMethodAndHandleException(() => { throw new Exception(); });

It's a little more clumsy but it get's the job done, albeit with more noise than should be required.

So is this a bug? I did some digging and found nothing that indicated other people had found the issue. I did find something interesting on Stack Overflow regarding event wireups being prevented from expression tree lambdas. However in that case the compiler error is clear in its problem with the statement, CS0832: An expression tree may not contain an assignment operator. In my case the compiler errors differ slightly from pre-compilation errors, and the fact that a semicolon is expected before the closing method call parenthesis seems to indicate that the throw compiler semantics are expecting a semicolon irrespective of the context of throw.

Just for a laugh I tried the same thing in VB.NET and after getting to grips with the unfamiliar (but strangely sensible) syntax of their lambdas I found that the same compiler errors are NOT present in VB.NET (probably because they don't use semicolons, and don't allow multi-line lambdas). More indication this is a defect rather than intended behaviour.

Sub Main()
    ExecuteMethodAndHandleException(Sub() Throw New Exception())
End Sub

Sub ExecuteMethodAndHandleException(ByVal methodThatWillThrowAnException As Action)
    Try
        methodThatWillThrowAnException()
    Catch ex As Exception
        ' ...
    End Try
End Sub


EDIT: Submitted this bug report to Microsoft. We'll see what happens to it.

No comments:

Post a Comment