2009-12-11 33 views
10

奇怪的一个,我不仍然得到,是这样的:异常表达式

说,

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表达式没有抓到!?我正在深入研究lambda,我无法理解它。是关于lambda的范围吗?范围变量?线程问题?我知道lambda没有多线程的本质,但你可以看到返回来自另一个由BeginSend创建的线程。在将实现转换为lambda之前,当我有一个处理EndSendAsyncCallBack方法时,这没问题。

任何帮助表示赞赏。 预先感谢您。

回答

17

你是对的,lamdas没有内在的异步性或多线程内置,但Socket.BeginSend。

会发生什么情况是try块将调用封装到BeginSend。如果该调用成功,则不会引发异常,并且封闭方法将返回,而不管其他线程上发生了什么。

如果在调用BeginSend期间发生异常,您的catch块将被调用。

但是,lambda表达式是一个异步回调,所以直到后面才会调用它。这发生在单独的线程上的独立调用堆栈中,所以try块在那里不起作用。

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

+0

很好解释马克,谢谢.. –

7

这与lambda无关。 BeginSend调用的代表在另一个线程上执行,因此该异常不会在具有catch语句的线程上抛出,因此它是未处理的。将您的异常处理与EndSend的代码一起使用。

欲了解更多信息,请参阅http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx

+0

这就是我第一次虽然,我只是想知道我是否可以避免这个:)但完全有道理...... –

+1

说'BeginSend'调用在另一个线程上执行不是有点误导? –

+0

安杰洛,我不知道你是什么误导你的意思。所有Beginxxx方法都在另一个线程上执行,而不是“开始”,“调用”,这些方法正在使用CPU的多I/O部分并自动处理线程。 –

1

由拉姆达定义匿名函数的调用异步发生。 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表单中定义代码内部的代码不会使代码更多地受到Try代码块的限制,如上面的MyCallBack。两者都会在包含Try块的函数之后运行,或者可能在其他线程中运行。

+0

事实上,我可以使用匿名方法,而不是一个Lambda,谢谢你的努力:) –

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

,因为我认为我是对的到现在为多,BeginSend将永远不会返回一个异常,所有的异常和结果在EndSend()方法上重新生成,所以我可以移动我的try catch块。

+0

除了ofcourse if(Socket === null),那么BeginSend给你一个NullReferenceException –