2012-05-23 32 views
11

Tôi đã nhìn thấy mô hình này một vài lần bây giờ:dùng cuối cùng thay vì bắt

 bool success = false; 
     try 
     { 
      DoSomething(); 
      success = true; 
     } 
     finally 
     { 
      if (!success) 
       Rollback(); 
     } 

Và tôi đã tự hỏi: Tại sao điều này tốt hơn so với sử dụng bắt buộc với rollbacks?

 try 
     { 
      DoSomething(); 
     } 
     catch 
     { 
      Rollback(); 
      throw; 
     } 

Sự khác biệt giữa hai cách đảm bảo thay đổi được khôi phục về lỗi là gì?

Trả lời

0

Mục tiêu rõ ràng ở đây là gây ra Rollback để được gọi trong trường hợp có bất kỳ lỗi nào. Cả hai đoạn mã đều hoàn thành mục tiêu này. Việc đầu tiên sử dụng một cuối cùng, mà luôn luôn chạy, mà xác minh rằng dòng cuối cùng của khối try đã đạt được thành công. Thứ hai bắt bất kỳ lỗi nào, cuộn lại giao dịch và sau đó ném lại ngoại lệ đã bị bắt. Kết quả của một trong hai đoạn trích là bất kỳ ngoại lệ nào được ném sẽ dẫn đến việc khôi phục trong khi vẫn sôi sục đến cấp độ tiếp theo.

Bạn đã đề cập rằng dự án đã được chuyển từ Java. Trong Java, bạn có thểre-throw an exception tương tự như cách bạn có thể sử dụng trong C# bằng cách sử dụng throw;. Bạn cũng có thể throw a new exception vẫn sẽ duy trì ngăn xếp cuộc gọi (et al). Thứ hai là một chút rõ ràng/đơn giản hơn trong C# (không phải bởi rất nhiều mặc dù) và đầu tiên có lợi thế của thực sự làm việc trong Java như được viết.

+0

Điều này có ý nghĩa. Tôi đã không nhận ra Java không cho phép bạn đúng cách rethrow excpetions. Và ở đây tôi đã nghĩ điều này sẽ liên quan đến các phần quan trọng và thích ... – configurator

+0

@configurator: Bây giờ bạn đề cập đến nó, tôi nghĩ có thể có một kết nối tới [Khu vực thực thi bị ràng buộc] (http://msdn.microsoft.com/en-us/library/ms228973.aspx). – dtb

+4

-1 cho "Trong Java không có cách nào để ném lại một ngoại lệ" - [ngoài 'ném e', nghĩa là] (http://stackoverflow.com/a/1097539/265143). –

1

finally luôn được thực hiện, không chỉ về ngoại lệ bắt. Được cấp, trong trường hợp cụ thể này, chỉ cần khôi phục khi có lỗi, nhưng dưới dạng chung, try-finally có thể hữu ích hơn cho quản lý tài nguyên (thường là bạn cần đảm bảo rằng bạn luôn luôn Close() hoặc Dispose() trong tổng số tài nguyên của bạn đúng cách). Đặc biệt nếu tác giả của mã này đến từ nền Java, nơi thành ngữ này phổ biến hơn.

+2

Nhưng khi không có ngoại lệ 'thành công' sẽ là sai, do đó, mệnh đề cuối cùng là một no-op. – configurator

+0

@configurator, vâng, hãy xem cập nhật của tôi. –

+0

Nhận xét nền Java có ý nghĩa với dự án mà tôi đã thấy điều này thực sự được chuyển từ Java. – configurator

2

Tuyên bố finally thường được sử dụng để làm sạch tài nguyên. Phương thức Rollback() có thể được sử dụng ở đó nếu ngoại lệ không phải là lý do duy nhất để quay trở lại giao dịch. Các phương pháp Close() hoặc Dispose() là các ứng cử viên chính để kết thúc trong khối cuối cùng.

Tuy nhiên, bạn không muốn thực thi bất kỳ điều gì có thể ném ngoại lệ.

+4

Câu trả lời này không có liên quan gì nhiều đến câu hỏi ... – configurator

+0

Việc xóa tài nguyên trong tuyên bố cuối cùng đơn giản, như tôi đã đề cập. Bằng cách này bạn không cần phải quay lại. –

+0

@configurator funny, nó được đánh giá cao nhất cho đến nay, và có những người khác tương tự như nó, có thể chỉnh sửa các câu hỏi để gợi ra phản ứng phù hợp hơn với mong muốn của bạn? –

4

Tôi đăng ở đây một số mã ngay cả khi nó không thực sự liên quan đến câu hỏi (sẽ xóa sau).

Với chương trình này:

using System; 

namespace testcs 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       try 
       { 
        foo(); 
        foo(); 
        foo(); 
       } 
       catch 
       { 
        throw; 
       } 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 

     private static void foo() 
     { 
      throw new Exception("oops"); 
     } 
    } 
} 

Các stack trace (! Nhìn vào số dòng) được bảo tồn nhưng bên trong main chức năng bạn sẽ thấy "dòng 19", dòng nơi throw là thay vì các đúng dòng nơi foo() đã được gọi (dòng 13).

+3

+1, lấy điểm, cảm ơn bạn đã dành thời gian tạo mẫu. Tôi không nghĩ rằng bạn nhất thiết cần phải xóa nó, vì nó minh họa sự khác biệt giữa hai phương pháp trong câu hỏi (và nó chắc chắn là quá dài cho một bình luận). – Heinzi

2

Tôi không chắc chắn nếu điều này không chỉ là anecdotal evidence, nhưng cá nhân tôi đã sử dụng mẫu này vì một lý do rất thực tế: Khi DoSomething ném ngoại lệ, trình gỡ lỗi Visual Studio sẽ vi phạm trong DoSomething. phiên bản, trong khi nó sẽ phá vỡ tại throw; trong phiên bản thứ hai. Điều này cho phép kiểm tra trạng thái ứng dụng trước khi Rollback làm sạch mọi thứ.

Screenshot

2

Nếu bạn không quan tâm trong mã đặc biệt này loại trừ bạn đang đánh bắt sử dụng:

try 
{ 
    DoSomething(); 
    ok = true; 
} 
finally 
{ 
    if(!ok)Rollback(); 
} 

này sẽ duy trì Call Stack ở dạng ban đầu của nó cho 100%. Ngoài ra nếu bạn sử dụng ngoại lệ maching như thế này:

try 
{ 
    DoSomething(); 
    ok = true; 
} 
catch(FirstExcetionType e1) 
{ 
    //do something 
} 
catch(SecondExcetionType e2) 
{ 
    //do something 
} 
catch(Exception e3) 
{ 
    //do something 
} 
finally 
{ 
    if(!ok)Rollback(); 
} 

sử dụng cuối cùng ở cuối có thể làm cho mã của bạn dễ đọc hơn so gọi rollback từ mọi lệnh catch duy nhất.

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