Исключение из лямбда-выражений

Странный, который я все еще не получаю, является этим:

Скажите,

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.

Любая справка ценится.Заранее спасибо.

10
задан nawfal 21 May 2013 в 13:09
поделиться

5 ответов

Вы правы, что lamdas не имеют встроенной асинхронности или многопоточности, в отличие от Socket.BeginSend.

Что происходит, так это то, что блок try инкапсулирует вызов BeginSend. Если этот вызов завершается успешно, исключение не генерируется и включающий метод возвращается, независимо от того, что происходит в других потоках.

Если во время вызова BeginSend возникает исключение, будут вызваны ваши блоки catch.

Однако лямбда Expression - это асинхронный обратный вызов, поэтому он будет вызываться позже. Это происходит в отдельном стеке вызовов в отдельном потоке, поэтому блок try там не действует.

Если вам нужна обработка ошибок для обратного вызова, вам нужно будет указать ее внутри самого обратного вызова (то есть внутри лямбда-выражения). ).

17
ответ дан 3 December 2019 в 16:29
поделиться

Это не связано с лямбдами. Делегат вызова BeginSend выполняется в другом потоке, поэтому исключение не генерируется в потоке, имеющем операторы catch , и поэтому оно не обрабатывается. Поместите обработку исключений вместе с кодом для EndSend .

Для получения дополнительной информации см. http://msdn.microsoft.com/en-us/library/38dxf7kt.aspx

7
ответ дан 3 December 2019 в 16:29
поделиться

Как уже указывалось в других ответах, вызов лямбда-выражения будет происходить асинхронно, и это причина того, что исключение не перехватывается.

Пример с асинхронными вызовами для чтения из файла:

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
ответ дан 3 December 2019 в 16:29
поделиться

Насколько я понимаю, BeginSend никогда не будет возвращать исключение, все исключения и результаты повторно возвращаются в методе EndSend (), поэтому я могу переместить свой попробуйте блоки catch.

0
ответ дан 3 December 2019 в 16:29
поделиться

Вызов анонимной функции, определенной лямбдой, происходит асинхронно. К тому времени блока 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 , или, возможно, во время, но в другом потоке.

1
ответ дан 3 December 2019 в 16:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: