2011-10-27 30 views
6

Tôi đã có một lớp gọi là giao diện SOAP và nhận được một mảng dữ liệu. Tuy nhiên, nếu yêu cầu này hết thời gian, nó sẽ đưa ra một ngoại lệ. Điều này là tốt. Tuy nhiên, tôi muốn chương trình của tôi cố thực hiện lại cuộc gọi này. Nếu nó hết thời gian, tôi muốn nó tiếp tục thực hiện cuộc gọi này cho đến khi nó thành công. Làm thế nào tôi có thể thực hiện điều này?Lặp lại một hàm trong C# cho đến khi nó không còn ném ngoại lệ

Ví dụ:

try 
{ 
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
} 
catch 
{ 
    ?? What Goes Here to FORCE the above line of code to rerun until it succeeds. 
} 
+3

Tăng thời gian chờ để nó không loại trừ ngoại lệ? – ChaosPandion

+0

Bạn có thể chỉ cần gọi lại phương thức từ khối catch, * NHƯNG * - điều gì xảy ra nếu dịch vụ ngừng hoạt động trong một khoảng thời gian dài? Bạn có muốn phương thức chạy đệ quy trong 24 giờ không? Tôi khuyên bạn nên giới hạn nó cho một số lần thử lại. – Tim

+5

Trong số tất cả các câu trả lời này, không một người nào bảo bạn bắt được một ngoại lệ cụ thể hơn. Điều gì sẽ xảy ra nếu khối thử của bạn chứa các đối tượng trong trạng thái không hợp lệ để có được 'salesOrderList'? Thử lại sẽ không bao giờ thành công. – Marc

Trả lời

14

Bạn chỉ cần lặp mãi mãi:

while (true) 
{ 
    try 
    { 
     salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
     break; // Exit the loop. Could return from the method, depending 
       // on what it does... 
    } 
    catch 
    { 
     // Log, I suspect... 
    } 
} 

Lưu ý rằng bạn nên gần như chắc chắn không thực sự vòng lặp mãi mãi. Bạn hầu như chắc chắn sẽ có số lần thử tối đa và có thể chỉ bắt được ngoại lệ cụ thể. Bắt tất cả các trường hợp ngoại lệmãi mãi có thể là đáng sợ ... tưởng tượng nếu salesOrderList (tên phương pháp độc đáo, btw) ném ArgumentNullException vì bạn đã có một lỗi và filter là null ... Bạn thực sự muốn tie lên 100 % CPU của bạn mãi mãi?

+1

Không thể (có khả năng) buộc tài nguyên hệ thống và/hoặc làm cho ứng dụng gọi điện không phản hồi? Không giống như giải pháp tốt nhất cho tôi ... – Tim

+0

@Tim: Tôi đã thêm đoạn dưới đây - về cơ bản mã trả lời câu hỏi trực tiếp, nhưng đoạn văn giải thích rằng đó có thể không phải là một ý tưởng hay :) –

+0

+1 cho cụ thể ngoại lệ, tôi đã nhập nhận xét của tôi về câu hỏi trong quá trình chỉnh sửa của bạn. – Marc

4

Nếu bạn không thể thay đổi thời gian chờ, dưới đây nên làm việc. salesOrdersArray nên được khởi tạo thành null.

while(salesOrdersArray == null) 
{ 
    try 
    { 
     salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    } 
    catch 
    { 
     // Log failure 
    } 
} 
+0

+1: Tôi thích điều này tốt hơn một chút so với câu trả lời của Jon. Tôi nghĩ rằng nó làm cho tình trạng kết thúc của vòng lặp rõ ràng hơn. – Brian

1

Nó không phải là một ident tốt để sử dụng ngoại lệ như luồng kiểm soát, nhưng điều này sẽ làm những gì bạn yêu cầu.

bool Caught = true; 
while (Caught) 
try 
{ 
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    Caught = false; 
} 
catch 
{ 
    Caught = true; 
} 
0
bool repeat = true; 
while (repeat) 
{ 
    try 
    { 
     salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
     repeat = false; 
    } 
    catch 
    { 
    } 
} 
0

Hãy thử

bool failed = false; 
do { 
try 
{ 
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
} 
catch 
{ 
    failed = true; 
} 
} while(failed); 

Các hành vi bạn là sau khi có thể gây ra một vòng lặp vô tận nếu điều này không bao giờ thành công mặc dù ...

0

Hãy thử một cái gì đó như thế này:

var failed = true; 
while (failed) 
{ 
    try 
    { 
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    failed = false; 
    } 
    catch 
    { 
    } 
} 

Edit: Wow! Tư tưởng lớn gặp nhau! :)

0

Mặc dù tôi sẽ không khuyên bạn làm điều này cho vô số lần, bạn có thể làm một chức năng riêng biệt ra khỏi đó một câu:

void GoConnect() 
{ 
    try 
    { 
     salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    } 
    catch 
    { 
     GoConnect(); 
    } 
} 
0
while(salesOrdersArray == null){ 

    try 
    { 
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    } 
    catch(salesOrderException e) 
    { 
    log(e.message); 
    } 
} 

này sẽ chạy mãi mãi, và đang sử dụng các ngoại lệ như một vòng lặp chậm. Có cách nào bạn có thể sửa đổi chức năng của bạn mà nó trả về null, thay vì ném một ngoại lệ? Nếu bạn mong đợi rằng cuộc gọi này sẽ thất bại thường xuyên, không sử dụng khối try/catch.

0

Tôi làm theo mô hình này để giải quyết vấn đề này:

public void Send(String data, Int32 attemptNumber) 
    { 
     try 
     { 
      yourCodeHere(data); 
     } 
     catch (WebException ex) 
     { 
      if (attemptNumber > 0) 
       Send(data, --attemptNumber); 
      else 
       throw new AttemptNumberExceededException("Attempt number exceeded!", ex); 
     } 
     catch (Exception ex) 
     { 
      //Log pourpose code goes here! 
      throw; 
     } 
    } 

Cố gắng mãi mãi dường như không phải là một ý tưởng tốt như bạn có thể sẽ có một quá trình vô hạn. Nếu bạn nghĩ rằng bạn cần nhiều nỗ lực để đạt được mục tiêu của bạn chỉ cần đặt số lượng lớn ở đây.

Cá nhân tôi nghĩ rằng nó khôn ngoan để chờ đợi một số mili giây, hoặc giây sau khi eac cố gắng Thread.Sleep (1000); trước callig Gửi (dữ liệu); Ví dụ: --- bạn có thể sử dụng biến attempNumber để thay đổi hoặc giảm thời gian chờ đợi này nếu bạn cho rằng nó là khôn ngoan cho kịch bản của bạn.

+0

'throw ex;' Đừng làm điều đó! – asawyer

+0

tại sao tôi không nên? Quan điểm của tôi cũng giống như Jon Skeet, bên dưới mã anh ta viết – renatoargh

+2

Đừng 'ném ex;' http://stackoverflow.com/questions/178456/what-is-the-proper-way-to-re-throw -ngoài-trong-c http: // stackoverflow.com/questions/22623/net-throwing-exceptions-best-practices – asawyer

1

Bạn phải đặt khối try/catch bên trong cấu trúc vòng lặp. Nếu bạn không muốn tiêu thụ 100% bộ xử lý của bạn đặt Thread.Sleep trong khối catch, do đó, mỗi khi một ngoại lệ xảy ra, nó sẽ chờ một thời gian, giải phóng bộ vi xử lý để làm những việc khác.

// iterate 100 times... not forever! 
for (int i = 0; i < 100; i++) 
{ 
    try { 
     // do your work here; 

     break; // break the loop if everything is fine 
    } catch { 
     Thread.Sleep(1000); 
    } 
} 

Bạn cũng có thể chỉ định loại ngoại lệ, để chỉ ngoại lệ thời gian chờ được xử lý và các loại ngoại lệ khác đi qua.

// iterate 100 times... not forever! 
for (int i = 0; i < 100; i++) 
{ 
    try { 
     // do your work here; 

     break; // break the loop if everything is fine 
    } catch (TimeOutException) { 
     Thread.Sleep(1000); 
    } 
} 

Lưu ý rằng, TimeOutException phải được thay thế bằng tên thật của ngoại lệ ... Tôi không biết đó có phải là tên thật không.

Cũng điều chỉnh thời gian ngủ, tính bằng millisec và số lần lặp lại, trong trường hợp tôi trình bày, 100 lần lặp lại 1000ms cho thời gian chờ tối đa là 1 phút và 40 giây cộng với thời gian hoạt động.

1

Tôi sẽ sử dụng giao dịch hàng đợi (MSMQ) để lưu trữ cuộc gọi dịch vụ. Một vòng lặp sẽ dequeue tin nhắn và gọi dịch vụ trong một TransactionScope, nếu cuộc gọi không thông báo dường như vẫn còn trong hàng đợi. Có thể xác định thời gian chờ của quá trình xóa thời gian chờ bằng cách thêm thời gian hết hạn vào tin nhắn. Giải pháp này là tốt nếu bạn thực sự muốn có một giải pháp đáng tin cậy vì tôi đoán rằng việc gọi đó là hoạt động rất quan trọng.

Các vấn đề liên quan