Странный, который я все еще не получаю, является этим:
Скажите,
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
не пойман!? Я шел глубже в лямбды, и я не могу понять это. Это об объеме лямбды? Переменные диапазона? Проблема потока? Я знаю, что лямбда не имеет никакой многопоточности по их характеру, но поскольку Вы видите, что возврат прибывает из другого потока, который создается BeginSend
. Прежде, чем преобразовать реализацию в лямбду это было в порядке, когда я имел AsyncCallBack
метод, обрабатывающий EndSend
.
Любая справка ценится.Заранее спасибо.
Вы правы, что lamdas не имеют встроенной асинхронности или многопоточности, в отличие от Socket.BeginSend.
Что происходит, так это то, что блок try инкапсулирует вызов BeginSend. Если этот вызов завершается успешно, исключение не генерируется и включающий метод возвращается, независимо от того, что происходит в других потоках.
Если во время вызова BeginSend возникает исключение, будут вызваны ваши блоки catch.
Однако лямбда Expression - это асинхронный обратный вызов, поэтому он будет вызываться позже. Это происходит в отдельном стеке вызовов в отдельном потоке, поэтому блок try там не действует.
Если вам нужна обработка ошибок для обратного вызова, вам нужно будет указать ее внутри самого обратного вызова (то есть внутри лямбда-выражения). ).
Это не связано с лямбдами. Делегат вызова BeginSend
выполняется в другом потоке, поэтому исключение не генерируется в потоке, имеющем операторы catch
, и поэтому оно не обрабатывается. Поместите обработку исключений вместе с кодом для EndSend
.
Для получения дополнительной информации см. http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx
Как уже указывалось в других ответах, вызов лямбда-выражения будет происходить асинхронно, и это причина того, что исключение не перехватывается.
Пример с асинхронными вызовами для чтения из файла:
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...
Насколько я понимаю, BeginSend никогда не будет возвращать исключение, все исключения и результаты повторно возвращаются в методе EndSend (), поэтому я могу переместить свой попробуйте блоки catch.
Вызов анонимной функции, определенной лямбдой, происходит асинхронно. К тому времени блока 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
перехватывает исключения, возникающие во время номинального выполнения его тела. Тот факт, что вы определили код внутри тела в виде лямбда-выражения, не делает этот код более зависимым от блока Try
, как в MyCallBack
выше. Оба будут запущены после функции, содержащей блок Try
, или, возможно, во время, но в другом потоке.