2010-03-03 23 views
7

Trong Python, có hữu ích mã này xử lý ngoại lệ:C#: tương đương của các thử python/catch/khác chặn

try: 
    # Code that could raise an exception 
except Exception: 
    # Exception handling 
else: 
    # Code to execute if the try block DID NOT fail 

Tôi nghĩ rằng nó rất hữu ích để có thể tách các mã mà thể tăng và ngoại trừ mã bình thường của bạn. Trong Python, điều này là có thể như được hiển thị ở trên, tuy nhiên tôi không thể tìm thấy bất cứ điều gì giống như nó trong C#.

Giả sử đối tượng địa lý hoặc đối tượng địa lý không tồn tại, thực tiễn tiêu chuẩn có đặt mã bình thường trong khối try hoặc sau khối catch không?

Lý do tôi hỏi là vì tôi có đoạn mã sau:

if (!IsReadOnly) 
{ 
    T newobj; 
    try 
    { 
     newobj = DataPortal.Update<T>(this); 

     List<string> keys = new List<string>(BasicProperties.Keys); 
     foreach (string key in keys) 
     { 
      BasicProperties[key] = newobj.BasicProperties[key]; 
     } 
    } 
    catch (DataPortalException) 
    { 
     // TODO: Implement DataPortal.Update<T>() recovery mechanism 
    } 
} 

nào yêu cầu mã thông thường là trong khối try bởi vì nếu nếu một ngoại lệ được nâng lên và sau đó xử lý, newobj sẽ được bỏ gán, nhưng nó cảm thấy khá không tự nhiên khi có nhiều mã trong khối thử không liên quan đến DataPortalException. Phải làm gì?

Cảm ơn

+1

Tôi luôn ghét sử dụng các khối try bắt vì điều này. Không có cách nào để tách mã đã ngắt và không phá mã. –

+1

Bỏ phiếu để đóng thành bản sao chính xác: http://stackoverflow.com/questions/1177438/c-try-catch-else – ChristopheD

+0

Điều này có thể trùng lặp, nhưng câu hỏi đó chưa bao giờ được trả lời đầy đủ. Sau khi đọc qua các câu trả lời, tôi thích ý tưởng của Daniel Newby nhất. –

Trả lời

0

Bạn có thể làm một cái gì đó như thế này:

if (!IsReadOnly) 
{ 
    T newobj = null; 
    try 
    { 
     newobj = DataPortal.Update<T>(this);  
    } 
    catch (DataPortalException) 
    { 
     // TODO: Implement DataPortal.Update<T>() recovery mechanism 
    } 
    if (newobj != null) 
    { 
     List<string> keys = new List<string>(BasicProperties.Keys); 
     foreach (string key in keys) 
     { 
      BasicProperties[key] = newobj.BasicProperties[key]; 
     } 
    } 
} 
0

đó sẽ là báo cáo kết quả sản phẩm nào giống như hit

try 
{ 
    somethingThatCanThrow(); 
} 
catch(Exception ex) 
{ 
    LogException(ex); 
    return; 
} 
ContinueFlow(); 
8

Tôi muốn để xem phần còn lại của mã bên ngoài hãy thử/nắm bắt để rõ ràng là nơi ngoại lệ bạn đang cố gắng bắt được đến từ đó và bạn không vô tình bắt được ngoại lệ mà bạn không cố gắng nắm bắt.

Tôi nghĩ tương đương gần nhất với Python try/catch/else là sử dụng biến boolean cục bộ để nhớ xem có ngoại lệ hay không.

bool success; 

try 
{ 
    foo(); 
    success = true; 
} 
catch (MyException) 
{ 
    recover(); 
    success = false; 
} 

if (success) 
{ 
    bar(); 
} 

Nhưng nếu bạn làm điều này, tôi sẽ hỏi tại sao bạn không hoàn toàn khôi phục ngoại lệ để bạn có thể tiếp tục như thể đã thành công hoặc hoàn toàn bị hủy bỏ bằng cách trả lại mã lỗi hoặc thậm chí chỉ để tuyên truyền ngoại lệ cho người gọi.

+1

+1 cho phần 'xử lý ngoại lệ đúng'. Nếu bạn không thể phục hồi từ ngoại lệ, có lẽ bạn nên ngừng làm những gì bạn đang làm ngay lập tức. Nếu bạn không thể dừng lại một cách duyên dáng, refactor để bạn có thể. – kibibu

+1

+1, nhưng tôi phải hỏi: làm thế nào là điều này tốt hơn so với việc đưa các cuộc gọi đến bar() ngay trước khi bắt? –

+1

@David: Với mã tôi đã đưa ra, nếu hàm 'bar' ném một MyException thì nó sẽ không bị bắt nhưng với gợi ý của bạn, nó sẽ bị bắt. Phương thức mà tôi đã cho thấy kết hợp chặt chẽ hơn với cấu trúc 'try: catch: else:' trong các ngoại lệ được nêu trong 'else' khác không bị bắt gặp. –

2

C# không có một khái niệm như vậy, vì vậy bạn chỉ là trái với ba lựa chọn,

  • đặt mã khác bên trong thử.
  • đặt mã khác bên ngoài khối try catch, sử dụng biến cục bộ để biểu thị thành công hay thất bại và nếu khối xung quanh mã khác của bạn.
  • đặt mã khác trong khối cuối cùng, sử dụng biến cục bộ để biểu thị thành công hay thất bại, và nếu khối chặn bạn mã khác.
2

Chỉ cần đặt khối "else" của bạn trước khi bắt đầu. Sau đó, nó sẽ chỉ thực thi nếu thực thi mã đạt đến điểm đó:

try 
{ 
    fee(); 
    fi(); 
    foe(); 
    fum(); 

    /// put your "else" stuff here. 
    /// It will only be executed if fee-fi-foe-fum did not fail. 
} 
catch(Exception e) 
{ 
    // handle exception 
} 

Cho rằng, tôi không thấy việc sử dụng try..catch ... else trừ khi có điều gì đó thiếu quan trọng trong mô tả của OP.

+5

Sự khác biệt là có 1 dòng dự kiến ​​sẽ ném một ngoại lệ và bạn đang mong đợi điều đó có thể xảy ra và bắt nó. Nếu một dòng khác đã ném ngoại lệ có thể là thứ bạn không muốn bắt, vì nó có thể chỉ ra một lỗi thực sự. – Davy8

+0

@ Davy8 trong trường hợp đó, bạn nên hoặc là a) chỉ bắt loại ngoại lệ cụ thể mà bạn mong đợi hoặc b) đặt mã mà bạn không mong đợi để tạo ngoại lệ ** bên ngoài ** của lần thử này..catch khối. Trong mọi trường hợp, bạn vẫn nên bắt bất kỳ ngoại lệ nào xảy ra để bạn có thể thất bại một cách duyên dáng. –

+1

Nó gần, nhưng nó không hoàn toàn tương đương. Nếu nó chỉ ở bên ngoài try/catch, nó sẽ thực hiện bất kể phần đầu tiên đã ném một ngoại lệ, nhưng nó chỉ nên thực hiện khi phần đầu tiên không ném. Có thể là loại ngoại lệ tương tự có thể được ném ra, vì vậy chỉ cần bắt một ngoại lệ cụ thể là một sự cải tiến, nhưng không chính xác như nhau. – Davy8

2

Cho phép tôi lặp lại ý tưởng từ similar StackOverflow question. Bạn không thể làm điều này trực tiếp, nhưng bạn có thể viết một phương thức đóng gói hành vi mà bạn cần. Nhìn vào câu hỏi ban đầu để xem cách triển khai phương thức (nếu bạn không quen thuộc với các biểu thức lambda và Func các đại biểu). Việc sử dụng có thể nhìn như thế này:

TryExceptRaise(() => { 
    // code that can throw exception 
    }, (Exception e) => { 
    // code to run in case of an exception 
    return (...); 
    },() => { 
    // code to run if there is no exception 
    return (...); 
    }); 
6

giải pháp Barbaric: tạo một lớp khác có nguồn gốc từ ngoại lệ, ném ra một thể hiện của nó ở phần cuối của khối try, và sử dụng catch (Else) {...} để xử lý những thứ khác.

Tôi cảm thấy rất bẩn.

+3

Tôi không biết phải làm gì ở đây - điều này * yêu cầu * một phiếu bầu -1, nhưng tôi thích thú đủ để ngần ngại làm như vậy. –

+1

Khác trong python không bắt tất cả các ngoại lệ khác. Khác, chỉ chạy khi không có ngoại lệ. – Nate

3

Điều này sẽ có thể bị giảm bớt nhưng không C# có goto (lưu ý tôi hầu như không có kiến ​​thức về C# vì vậy tôi không biết liệu điều này có hoạt động không).

những gì về một cái gì đó giống như

try 
{ 
... 
} 
catch(Exception ex) 
{ 
... 
goto Jump_past_tryelse 
} 
...//Code to execute if the try block DID NOT fail 

Jump_past_tryelse: 
... 
+0

Tôi gần như cung cấp cho bạn một +1 chỉ đơn giản là để cung cấp ra toàn bộ quán rượu với 'goto' của bạn! – amelvin

+0

Chỉ gần như, tâm trí. – amelvin

+3

"cung cấp toàn bộ quán rượu" ==? –

0
if (!IsReadOnly) 
     { 
      T newobj; 
      bool Done; 
      try 
      { 
       newobj = DataPortal.Update<T>(this); 
       List<string> keys = new List<string>(BasicProperties.Keys); 
       foreach (string key in keys) 
       { 
        BasicProperties[key] = newobj.BasicProperties[key]; 
       } 
       Done = true; 
      } 
      catch (DataPortalException) 
      { 
       // TODO: Implement DataPortal.Update<T>() recovery mechanism 
       Done = false; 
      } 
      finally 
      { 
       if (newobj != null && Done == false) 
       { 
        List<string> keys = new List<string>(BasicProperties.Keys); 
        foreach (string key in keys) 
        { 
         BasicProperties[key] = newobj.BasicProperties[key]; 
        } 
       } 
      } 
     } 
0

Với C# phiên bản 7, bạn có thể sử dụng chức năng địa phương bắt chước hành vi này:

Ví dụ 1:

void Main() 
{ 
    void checkedCode() 
    { 
     try 
     { 
      foo(); 
     } 
     catch (Exception ex) 
     { 
      recover(); 
      return; 
     } 
     // ElseCode here 
    } 
    checkedCode(); 
} 

Nếu bạn thích cú pháp lambda, bạn cũng có thể khai báo một phương pháp chạy

void Run(Action r) { r(); } 

mà chỉ cần có mặt ở đó một lần trong mã của bạn, và sau đó sử dụng các mô hình cho các phương pháp vô danh như sau

Ví dụ 2:

Run(() => { 
    try 
    { 
     foo(); 
    } 
    catch (Exception) 
    { 
     recover(); 
     return; 
    } 
    // ElseCode here 
}); 

bất cứ nơi nào bạn cần kèm theo mã trong ngữ cảnh an toàn.


Ghi chú:

  • Trong cả hai ví dụ một bối cảnh chức năng được tạo ra để chúng ta có thể sử dụng return; để thoát về lỗi.
  • Mẫu tương tự như được sử dụng trong Ví dụ 2 bạn có thể tìm thấy trong JavaScript: Self-invoking anonymous functions (ví dụ: JQuery sử dụng chúng). Bởi vì trong C# bạn không thể tự gọi, phương thức trợ giúp Run được sử dụng.
  • Kể từ Run không phải là một chức năng của địa phương, Ví dụ 2 làm việc với các phiên bản cũ C# cũng
Các vấn đề liên quan