2009-12-11 70 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 –