lambda表达式的异常

时间:2009-12-11 12:02:04

标签: c# exception tcp .net-3.5 lambda

奇怪的是,我还没有得到,是这样的:

说,

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.
}

我不明白为什么没有捕获返回ObjectDisposedException的lambda表达式!?我正在深入研究lambdas,我无法理解它。是关于lambda的范围吗?范围变量?线程问题?我知道lambda本质上没有多线程,但是你可以看到返回来自另一个由BeginSend创建的线程。在将实现转换为lambda之前,当我使用AsyncCallBack方法处理EndSend时,这是可以的。

任何帮助表示赞赏。 提前谢谢。

5 个答案:

答案 0 :(得分:17)

你是正确的,lamdas没有固有的异步性或内置的多线程,但Socket.BeginSend确实如此。

try块封装了对BeginSend的调用。如果该调用成功,则抛出异常并且无论其他线程发生什么,封闭方法都会返回。

如果在调用BeginSend期间发生异常,则会调用catch块。

但是,lambda表达式是一个异步回调函数,所以直到稍后才会调用它。这发生在一个单独的线程上的单独的callstack中,因此try块在那里没有效果。

如果要对回调进行错误处理,则需要在回调本身内(即在lambda内)指定它。

答案 1 :(得分:7)

与lambdas无关。 BeginSend调用的委托在另一个线程上执行,因此不会在具有catch语句的线程上抛出异常,因此它未被处理。将您的异常处理与EndSend的代码一起放置。

有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx

答案 2 :(得分:1)

对lambda定义的匿名函数的调用是异步发生的。那个try块早就过去了。

您的代码与: -

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

现在你可以定义一个函数: -

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

然后上面的代码可能变成: -

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

在这种情况下,它几乎完全相同。关键是Try陷阱在其身体的名义执行期间发生的异常。您以lambda的形式在body中定义代码的事实不会使该代码更像Try块作为上面的MyCallBack。两者都将在包含Try块的函数之后运行,或者可能在不同的线程期间运行。

答案 3 :(得分:0)

正如在其他答案中已经说过的那样,对lambda的调用将异步发生,这就是异常未被捕获的原因。

从文件中读取异步调用的示例:

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);

输出结果为:

Thread: 1 - Before asynch call...
Thread: 1 - After asynch call...
Thread: 3 - Callback called...

答案 4 :(得分:0)

尽管我认为我到现在为止,但BeginSend永远不会返回异常,所有的excpetions和结果都会在EndSend()方法中重新出现,所以我可以移动我的try catch块。