Đang chờ đợi trong khối bắt


85

Tôi có mã sau:

WebClient wc = new WebClient();
string result;
try
{
  result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
}
catch
{
  result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
}

Về cơ bản, tôi muốn tải xuống từ một URL và khi nó không thành công với một ngoại lệ, tôi muốn tải xuống từ một URL khác. Tất nhiên cả hai thời gian đều không đồng bộ. Tuy nhiên, mã không biên dịch, vì

lỗi CS1985: Không thể đợi trong phần nội dung của mệnh đề bắt

OK, nó bị cấm vì bất kỳ lý do gì nhưng mẫu mã chính xác ở đây là gì?

BIÊN TẬP:

Tin tốt là C # 6.0 có thể sẽ cho phép các cuộc gọi chờ đợi cả trong các khối bắt và cuối cùng .

Câu trả lời:


103

Cập nhật: C # 6.0 hỗ trợ đang chờ đón


Câu trả lời cũ : Bạn có thể viết lại mã đó để di chuyển awaitkhỏi catchkhối bằng cách sử dụng cờ:

WebClient wc = new WebClient();
string result = null;
bool downloadSucceeded;
try
{
  result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
  downloadSucceeded = true;
}
catch
{
  downloadSucceeded = false;
}

if (!downloadSucceeded)
  result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );

7
Cảm ơn svick, điều đó khá rõ ràng, còn gì tốt hơn, kết nối nhiều hơn với async?
György Balássy

Tôi không nghĩ rằng bất cứ điều gì như vậy tồn tại.
svick

3
Trong trường hợp của bạn, bạn cũng có thể sử dụng các nhiệm vụ liên tục. Nhưng mã trong svickcâu trả lời của rõ ràng hơn mã sử dụng liên tục.
Stephen Cleary

16
Nếu bạn thậm chí cần ném lại ngoại lệ mà không làm mất callstack, bạn cũng có thể sử dụng System.Runtime.ExceptionServices.ExceptionDispatchInfolớp tĩnh. Đơn giản chỉ cần gọi ExceptionDispatchInfo.Capture(ex)trong khối bắt của bạn và lưu trữ giá trị trả về, ngoại lệ đã bắt, trong một biến cục bộ. Sau khi hoàn tất với mã không đồng bộ của mình, bạn có thể sử dụng mã capturedException.Throw()này sẽ tạo lại ngoại lệ ban đầu một cách chính xác.
Etienne Maheu

tuyệt vời kỹ thuật
Zia Ur Rahman


9

Điều này có vẻ hiệu quả.

        WebClient wc = new WebClient();
        string result;
        Task<string> downloadTask = wc.DownloadStringTaskAsync(new Uri("http://badurl"));
        downloadTask = downloadTask.ContinueWith(
            t => {
                return wc.DownloadStringTaskAsync(new Uri("http://google.com/")).Result;
            }, TaskContinuationOptions.OnlyOnFaulted);
        result = await downloadTask;

6

Hãy thử cái này:

         try
        {
            await AsyncFunction(...);
        }

        catch(Exception ex)
        { 
            Utilities.LogExceptionToFile(ex).Wait();
            //instead of "await Utilities.LogExceptionToFile(ex);"
        }

(Xem phần Wait()kết)


4

Sử dụng C # 6.0. xem liên kết này

public async Task SubmitDataToServer()
{
  try
  {
    // Submit Data
  }
  catch
  {
    await LogExceptionAsync();
  }
  finally
  {
    await CloseConnectionAsync();
  }
}

1

Mẫu tôi sử dụng để ném lại ngoại lệ sau khi chờ tác vụ dự phòng:

ExceptionDispatchInfo capturedException = null;
try
{
  await SomeWork();
}
catch (Exception e)
{
  capturedException = ExceptionDispatchInfo.Capture(e);
}

if (capturedException != null)
{
  await FallbackWork();
  capturedException.Throw();
}

1

Bạn có thể sử dụng biểu thức lambda như sau:

  try
    {
        //.....
    }
    catch (Exception ex)
    {
        Action<Exception> lambda;

        lambda = async (x) =>
        {
            // await (...);
        };

        lambda(ex);
    }

Điều này làm cho lambda async void, không nên được sử dụng, trừ khi bạn phải.
svick

0

Bạn có thể đặt awaitsau khối catch theo sau là a labelvà đặt một gotokhối try. (Không, thực sự! Goto không tệ như vậy!)


0

Trong một trường hợp tương tự, tôi không thể chờ đợi trong một khối bắt. Tuy nhiên, tôi đã có thể đặt cờ và sử dụng cờ trong câu lệnh if (Mã bên dưới)

---------------------------------------...

boolean exceptionFlag = false; 

try 
{ 
do your thing 
} 
catch 
{ 
exceptionFlag = true; 
} 

if(exceptionFlag == true){ 
do what you wanted to do in the catch block 
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.