2009-12-11 15 views
10

Garip bir ifadelerde şudur ki: ObjectDisposedException ile döner lambda ifadesi yakalanmayan neden anlamıyorumİstisna hala alamadım

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

!? Lambdalara daha derine iniyordum ve anlayamıyorum. Lambda'nın kapsamı hakkında mı? Aralık Değişkenleri? Konu sorunu? Lambda'nın doğası gereği çok iş parçacığı olmadığını biliyorum, ancak dönüşün BeginSend tarafından oluşturulan başka bir iş parçacığından geldiğini görebilirsiniz. Uygulamayı bir lambda'ya dönüştürmeden önce, EndSend'u işleyen bir AsyncCallBack yöntemine sahip olduğumda bu tamam oldu.

Herhangi bir yardım için teşekkür ederiz. Önceden teşekkür ederiz.

cevap

17

Lamdaşların yerleşik uyumsuzluk veya çoklu iş parçacığına sahip olmadıkları doğru, ancak Socket.BeginSend'in yaptığı doğrudur.

Ne olur, try bloğu, BeginSend'e çağrıyı kapsüller. Bu çağrı başarılı olursa, diğer iş parçacıklarında ne olursa olsun hiçbir istisna atılmaz ve kapatma yöntemi geri döner.

BeginSend çağrısı sırasında bir istisna meydana gelirse, catch bloklarınız çağrılır.

Ancak, lambda ifadesi bir zaman uyumsuz geri aramadır, bu nedenle daha sonraya kadar çağrılmayacaktır. Bu, ayrı bir iş parçacığı üzerinde ayrı bir arama işleminde gerçekleşir, böylece try bloğu orada etkin değildir.

Geri arama için hata işlemeyi istiyorsanız, geri aramada belirtmeniz gerekir (yani, lambda içinde).

+0

İyi açıkladı Mark, teşekkürler .. –

7

Bu lambdas ile ilgili değildir. BeginSend çağrısının temsilcisi, başka bir iş parçacığında yürütülür, bu nedenle istisna, catch ifadelerine sahip iş parçacığına atılmaz ve dolayısıyla işlenmez. İstisna işleminizi EndSend koduyla birlikte yerleştirin.

fazla bilgi için lambda tarafından tanımlanan anonim işlevine çağrı uyumsuz olur http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx

+0

Ne olsa ben ilk önce, ben sadece bunu önlemek olabilir merak ediyorum :) ama tam anlamıyla yapar ... –

+1

Başka bir iş parçacığı üzerinde 'BeginSend' çağrısı yürütüyor söyleyerek yanıltıcı değil tür? –

+0

Angelo, ne demek istediğini anlamıyorum. Tüm Beginxxx yöntemleri, "başlatılmış", "çağrılan" bir başka dizide yürütülür, bu yöntemler CPU'nun Çoklu I/O bölümünü kullanır ve otomatik olarak iş parçacığı kullanır. –

1

bakın. Deneme bloğu o zamana kadar gitmiş olacak.

Kodun aynıdır: -

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

Artık bir işlevi tanımlanmış olabilir: -

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

ve daha sonra yukarıdaki kod haline gelebilir: -

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

Bu durumdaki hemen hemen hepsi aynı şey. Buradaki nokta, Try, vücudunun nominal çalışması sırasında oluşan istisnaları yakalar. Bir lambda biçiminde beden içindeki kodu tanımladığınız gerçek, bu kodu Try bloğuna yukarıdaki MyCallBack olarak daha fazla tabi tutmaz. Her ikisi de Try bloğu içeren veya muhtemelen farklı bir iş parçacığı üzerinde bulunan işlevden sonra çalıştırılacaktır.

+0

Gerçekten de bir Lambda yerine Anonim Metodu kullanabilirim, çabalarınız için teşekkür ederim :) –

0

Diğer cevaplarda daha önce belirtildiği gibi, lambdaya yapılan çağrı eşzamansız olarak gerçekleşecek ve bu durum istisnasız yakalanmama sebebidir.

asenkron ile örnek bir dosyadan okumak için çağırır:

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

çıkışı olacaktır:

Thread: 1 - Before asynch call... 
Thread: 1 - After asynch call... 
Thread: 3 - Callback called... 
0
i şu anda kadar olduğumu düşünüyorum kadar olduğu gibi

, BeginSend asla dönecektir Bir istisna, tüm excpetions ve sonuç EndSend() yönteminde yeniden yayınlanmıştır, bu yüzden try catch bloklarımı hareket ettirebilirim.

+0

Eğer (Socket === null) ise, BeginSend size bir NullReferenceException verirse –