views:

114

answers:

5

Strange one that i don't still get, is this:

Say,

try
{
    stateClient.Socket.BeginSend(messagePrefixed, 0, messagePrefixed.Length,
        SocketFlags.None, ar => stateClient.Socket.EndSend(ar), stateClient);
}
catch (SocketException ex)
{
    // Handle SocketException.
}
catch (ObjectDisposedException ex)
{
    // Handle ObjectDisposedException.
}

I don't understand why if lambda expression returns with ObjectDisposedException is not catched!? I just going deeper into Lambda's and this i cant understand it, is that about scope of Lambda's? Range Variables? Thread issue? I know Lambda's is not multithreading by they're nature but as you can see the return comes from another thread which created by the BeginSend. Before convert the implementation into a Lambda this was ok when i had an AsyncCallBack method handling the EndSend().

Any help appreciated. Thank you in advance.

+7  A: 

It isn't related to lambdas. The delegate of the BeginSend call executes on another thread, so the exception is not thrown on the thread that has the catch statements and thus it is unhandled. Place your exception handling along with the code for EndSend.

For more information see http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx

Brian Rasmussen
Thats what i first though, i was just wondering if i could avoid this :) but makes complete sense...
Saying that the `BeginSend` call executes on another thread isn't kind of misleading?
João Angelo
Angelo, i dont know what misleading you mean. All Beginxxx methods are executing on another thread than the one "started", "called", those methods are using the Multi I/O part of the CPU and automatically handling threading.
What's misleading is that the code for BeginSend executes on the _current_ thread. It's implementation triggers some more work on another thread, but the call itself is happening in this thread, since you called it there.
Bahbar
@Joäo: You're right that could easily be misinterpreted. I have reworded it so hopefully it is clear now. Thanks for pointing that out.
Brian Rasmussen
+1  A: 

The call to the anonymous function defined by the lambda happens asynchronously. The try block will be long gone by then.

You code is the same as:-

AsyncCallBack cb = delegate(AsyncCallback ar) { stateClient.Socket.EndSend(ar); }
stateClient.Socket.BeginSend(messagePrefixed, 0, messagePrefixed.Length,
   SocketFlags.None, cb, stateClient);

Now you could have defined a function:-

void MyCallBack(AsyncCallback ar) { stateClient.Socket.EndSend(ar); }

and then the code above could become:-

stateClient.Socket.BeginSend(messagePrefixed, 0, messagePrefixed.Length,
   SocketFlags.None, MyCallBack, stateClient);

Its all pretty much the same thing in this case. The point is that Try traps exceptions that occur during the nominal execution of its body. The fact the you defined code inside the body in the form of a lambda doesn't make that code any more subject to the Try block as the MyCallBack above. Both would be run after the function that contains Try block or possibly during but on a different thread.

AnthonyWJones
Indeed i could use Anonymous Method instead of a Lambda, thank you for your effort :)
+6  A: 

You are correct that lamdas have no inherent asynchronicity or multithreading built-in, but Socket.BeginSend does.

What happens is that the try block encapsulates the call to BeginSend. If that call succeeds, no exception is thrown and the enclosing method returns, no matter what happens on other threads.

If an exception happens during the call to BeginSend, your catch blocks will be invoked.

However, the lambda expression is an asynchronous callback, so it's not going to be invoked until later. This happens in a separate callstack on a separate thread, so the try block is not in effect there.

If you want error handling for the callback, you will need to specify it inside the callback itself (that is, inside the lambda).

Mark Seemann
Well explained Mark, thank you..
A: 

As already stated in other answers the call to the lambda will happen asynchronously and that's the reason for the exception not being caught.

An example with asynchronous calls to read from a file:

File.WriteAllText("example.txt", new string('0', 2048));

Stream s = File.OpenRead("example.txt");

var buffer = new byte[1024];

Console.WriteLine(
    "Thread: {0} - Before asynch call...", 
    Thread.CurrentThread.ManagedThreadId);

s.BeginRead(
    buffer, 
    0, 
    1024, 
    ar =>
    {
        Thread.Sleep(100); // Simulate a long op
        Console.WriteLine(
            "Thread: {0} - Callback called...", 
            Thread.CurrentThread.ManagedThreadId);
    }
    , 0);

Console.WriteLine(
    "Thread: {0} - After asynch call...",
    Thread.CurrentThread.ManagedThreadId);

// Wait for callback to be executed
Thread.Sleep(2000);

The output would be:

Thread: 1 - Before asynch call...
Thread: 1 - After asynch call...
Thread: 3 - Callback called...
João Angelo
A: 

As much as i think i'm right till now, BeginSend will never return an exception, all excpetions and result are rerurned on the EndSend() method, so there is that i can move my try catch blocks.

Except ofcourse if (Socket === null) then BeginSend gives you a NullReferenceException