Tại sao bắt và suy nghĩ lại một ngoại lệ trong C #?


557

Tôi đang xem bài viết C # - Đối tượng truyền dữ liệu về các DTO tuần tự hóa.

Bài viết bao gồm đoạn mã này:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

Phần còn lại của bài viết có vẻ lành mạnh và hợp lý (với một người mới), nhưng việc ném thử đó ném WtfException ... Điều này có hoàn toàn tương đương với việc không xử lý ngoại lệ không?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

Hay tôi thiếu một cái gì đó cơ bản về xử lý lỗi trong C #? Nó khá giống với Java (trừ các trường hợp ngoại lệ được kiểm tra), phải không? ... Đó là, cả hai đều tinh chế C ++.

Câu hỏi về Stack Overflow Sự khác biệt giữa việc bắt lại tham số ít hơn và không làm gì cả? dường như ủng hộ sự tranh giành của tôi rằng try-Catch-throw là-không-op.


BIÊN TẬP:

Chỉ cần tóm tắt cho bất cứ ai tìm thấy chủ đề này trong tương lai ...

ĐỪNG

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

Thông tin theo dõi ngăn xếp có thể rất quan trọng để xác định nguyên nhân gốc rễ của vấn đề!

LÀM

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Nắm bắt các ngoại lệ cụ thể hơn trước các ngoại lệ ít cụ thể hơn (giống như Java).


Người giới thiệu:


8
Tóm tắt tốt; thêm điểm cho bao gồm cả khối cuối cùng.
Fredrik Mörk

tôi muốn thêm rằng bạn có thể sử dụng "throw;" thậm chí còn hữu ích hơn bằng cách thêm các tham số đã được gửi đến phương thức trong bộ sưu tập e.Data trước khi "throw;" tuyên bố
Michael Bahig

@MickTheWarMachineDesigner (và họa sĩ bán thời gian). Huh? Bạn đang nói về việc xử lý microshite Suckwell (có thể là năm 2005 trở đi, đối với tất cả những gì tôi biết) ngoại lệ. Tôi đã nói về xử lý ngoại lệ nói chung. Và vâng, tôi đã học được một số từ khi tôi đăng bài này CẦN BỐN NĂM NĂM .... Nhưng vâng, tôi thú nhận rằng bạn có điểm hợp lệ, nhưng tôi nghĩ bạn đã bỏ lỡ điểm thực sự; Nếu bạn hiểu sự lệch hướng của tôi? Câu hỏi này là về xử lý ngoại lệ CHUNG trong C #; và cụ thể hơn về các trường hợp ngoại lệ đang hồi phục ... của TẤT CẢ các loại. Mát mẻ?
corlettk

Vui lòng xem xét chuyển phần tóm tắt chỉnh sửa trong câu hỏi của bạn sang câu trả lời của riêng nó. Để biết lý do tại sao, hãy xem Chỉnh sửa tự trả lời câu hỏiTrả lời được nhúng trong câu hỏi .
DavidRR

2
Có ai không nhận thấy phần "Xuất hiện"? Nghe có vẻ như mã đã đi ị!
Jason Loki Smith

Câu trả lời:


430

Đầu tiên; cách mà đoạn mã trong bài viết thực hiện nó là xấu xa. throw exsẽ thiết lập lại ngăn xếp cuộc gọi ngoại lệ đến điểm có câu lệnh ném này; mất thông tin về nơi thực sự ngoại lệ được tạo ra.

Thứ hai, nếu bạn chỉ bắt và ném lại như vậy, tôi thấy không có giá trị gia tăng nào, ví dụ mã ở trên sẽ tốt như vậy (hoặc, được cung cấp throw exbit, thậm chí tốt hơn) mà không cần thử bắt.

Tuy nhiên, có những trường hợp bạn có thể muốn bắt và suy nghĩ lại một ngoại lệ. Ghi nhật ký có thể là một trong số đó:

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}

6
@Fredrick, chỉ cần fyi (mặc dù bạn có thể biết) nếu bạn sẽ không sử dụng exđối tượng đó, thì không cần phải khởi tạo nó.
Eoin Campbell

78
@Eoin: Nếu nó không được khởi tạo thì việc đăng nhập nó sẽ khá khó khăn.
Sam Axe

30
Đúng, tôi nghĩ rằng "cái ác" là đúng ... hãy xem xét trường hợp ngoại lệ con trỏ null được ném ở đâu đó từ một khối mã lớn. Thông điệp là vanilla, không có dấu vết ngăn xếp mà bạn để lại với "một cái gì đó không có ở đâu đó". KHÔNG tốt khi sản xuất bị chết; và bạn KHÔNG CÓ ít phút để giải quyết vấn đề của flamin, và loại bỏ hoặc khắc phục nó ... Xử lý ngoại lệ tốt đáng giá bằng vàng.
corlettk

4
Điều đó có đúng với Java không ... "ném" so với "ném ex"?
JasonStoltz

8
@Jason, xem câu hỏi này . Trong Java, throw exkhông khởi động lại stacktrace.
Matthew Flaschen

117

Đừng làm điều này,

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

Bạn sẽ mất thông tin theo dõi ngăn xếp ...

Hoặc là làm

try { ... }
catch { throw; }

HOẶC LÀ

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

Một trong những lý do bạn có thể muốn nghĩ lại là nếu bạn xử lý các ngoại lệ khác nhau, ví dụ:

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}

7
Tại sao không bỏ qua việc bắt {throw} hoàn toàn?
AnthonyWJones

3
vẫn còn giá trị trong việc để lại bắt {ném; } ở dưới cùng của một danh sách các loại ngoại lệ cụ thể bắt với lý do nó chứng minh tác giả đã xem xét trường hợp này, mặc dù một nhận xét có thể đủ. Không đoán được khi bạn đọc mã là một điều tốt.
annakata

87
Vì một số lý do, tên của SQLException làm phiền tôi.
Michael Myers

13
Cái bẫy đó (Ngoại lệ) {ném Ngoại lệ mới (...)} là điều bạn không bao giờ nên làm, đơn giản là vì bạn đang che giấu thông tin ngoại lệ và khiến việc lọc ngoại lệ trở nên khó khăn hơn trong cuộc gọi. Lần duy nhất bạn nên bắt một loại ngoại lệ và ném một loại ngoại lệ khác là khi bạn đang thực hiện một lớp trừu tượng và bạn cần chuyển đổi một loại ngoại lệ dành riêng cho nhà cung cấp (ví dụ: SqlException so với XmlException) thành một loại chung hơn (ví dụ DataLoadingException).
jammycakes

3
@dark_perinf bạn nên kiểm tra trước đối số đó, ở đầu phương thức và ném ArgumentNullException ở đó (thất bại nhanh).
Andrei Bozantan

56

C # (trước C # 6) không hỗ trợ "ngoại lệ được lọc" của CIL, mà VB thực hiện, do đó, trong C # 1-5, một lý do để ném lại một ngoại lệ là bạn không có đủ thông tin tại thời điểm bắt () để xác định xem bạn có thực sự muốn bắt ngoại lệ hay không.

Ví dụ, trong VB bạn có thể làm

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

... sẽ không xử lý MyExceptions với các giá trị ErrorCode khác nhau. Trong C # trước v6, bạn sẽ phải bắt và ném lại MyException nếu ErrorCode không phải là 123:

try 
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

Vì C # 6.0, bạn có thể lọc giống như với VB:

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}

2
Dave, nhưng (ít nhất là trong java) bạn sẽ không ném MyException "chung chung", bạn sẽ xác định một loại ngoại lệ CỤ THỂ và ném nó, cho phép nó được phân biệt theo loại trong khối bắt ... Nhưng vâng , nếu bạn không phải là kiến ​​trúc sư của trường hợp ngoại lệ (tôi đang nghĩ rằng SQLException (lại là Java) của JDBC, thì chung chung ghê tởm và phơi bày phương thức getErrorCode () ... Hmmm ... Bạn đã có một điểm, đó chỉ là Tôi nghĩ rằng có một cách tốt hơn để làm điều đó, nếu có thể. Chúc mừng Mate. Tôi đánh giá cao thời gian của bạn, rất nhiều. Keith.
corlettk

1
Chà, câu hỏi là "Tại sao bắt và rút lại Ngoại lệ trong C #?", Và đây là một câu trả lời. =] ... và ngay cả với các trường hợp ngoại lệ chuyên biệt, Bộ lọc ngoại lệ có ý nghĩa: hãy xem xét trường hợp bạn đang ở, giả sử, xử lý một SqlTimeoutException và SqlConnectionResetException, cả hai đều là SqlException. Bộ lọc ngoại lệ cho phép bạn bắt SqlException chỉ khi nó là một trong hai, vì vậy thay vì làm lộn xộn việc thử / bắt của bạn với việc xử lý giống hệt nhau cho hai điều này, bạn có thể "bắt SqlException ex khi ex là SqlTimeoutException Hoặc ex là SqlConnectionResetException". (Tôi không phải Dave btw)
bzlm

3
Các ngoại lệ được lọc đang đến trong C # 6!
Ngài Crispalot 7/07/2015

14

Lý do chính của tôi để có mã như:

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

là vì vậy tôi có thể có một điểm dừng trong bẫy, có một đối tượng ngoại lệ được khởi tạo. Tôi làm điều này rất nhiều trong khi phát triển / gỡ lỗi. Tất nhiên, trình biên dịch cung cấp cho tôi một cảnh báo về tất cả các e chưa sử dụng và lý tưởng là chúng nên được gỡ bỏ trước khi xây dựng bản phát hành.

Họ là tốt đẹp trong khi gỡ lỗi mặc dù.


1
Vâng, tôi sẽ trả cái đó, nhưng vâng, bạn sẽ không muốn thấy rằng trong mã được xuất bản ... ergo: Tôi sẽ xấu hổ khi xuất bản nó ;-)
corlettk

25
Trên thực tế, điều này không cần thiết - trong Visual Studio, bạn có thể đặt trình gỡ lỗi phá vỡ khi ném ngoại lệ và nó sẽ hiển thị các chi tiết ngoại lệ trong cửa sổ thanh tra cho bạn.
jammycakes

8
Nếu bạn muốn sử dụng một số mã CHỈ trong quá trình gỡ lỗi, hãy sử dụng #if DEBUG ... #endif và bạn không cần phải xóa các dòng này
Michael Freidgeim

1
Ya, tôi đã làm điều đó một vài lần bản thân mình. Thỉnh thoảng người ta sẽ thoát ra một bản phát hành. @jammycakes Vấn đề với ngoại lệ của Visual Studio là, đôi khi ngoại lệ tôi muốn không phải là trường hợp duy nhất (hoặc thậm chí chỉ có một loại) bị ném. Vẫn không biết về một điều kiện điểm dừng với "phá vỡ nếu bị bỏ qua bởi ngoại lệ". Cho đến khi, điều này sẽ vẫn hữu ích. Michael Freidgeim: #if DEBUGxung quanh CẢ HAI try {} catch () {...}hơi lộn xộn và, thẳng thắn, khiến tôi thấy khó chịu ... Nói chung, bộ xử lý trước nói chung, không phải là bạn của tôi.

11

Một lý do hợp lệ để lấy lại ngoại lệ có thể là bạn muốn thêm thông tin vào ngoại lệ hoặc có thể bao bọc ngoại lệ ban đầu trong một trong những cách tạo của riêng bạn:

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}

Thanx, gói ngoại lệ (đặc biệt là bị xiềng xích) hoàn toàn lành mạnh ... những gì không lành mạnh đang bắt một ngoại lệ chỉ để bạn có thể tặc lưỡi, hoặc tệ hơn là ăn nó.
corlettk

10

Điều này có chính xác tương đương với việc không xử lý ngoại lệ nào không?

Không chính xác, nó không giống nhau. Nó đặt lại stacktrace của ngoại lệ. Mặc dù tôi đồng ý rằng đây có thể là một sai lầm, và do đó là một ví dụ về mã xấu.


8

Bạn không muốn ném ex - vì điều này sẽ làm mất ngăn xếp cuộc gọi. Xem Xử lý ngoại lệ (MSDN).

Và vâng, thử ... bắt không làm gì hữu ích (ngoài việc mất ngăn xếp cuộc gọi - vì vậy nó thực sự tồi tệ hơn - trừ khi vì một lý do nào đó bạn không muốn tiết lộ thông tin này).


Bạn không mất toàn bộ ngăn xếp cuộc gọi khi bạn sử dụng throw ex, bạn chỉ mất một phần của ngăn xếp cuộc gọi từ điểm xảy ra ngoại lệ cao hơn trong ngăn xếp cuộc gọi của nó. Nhưng bạn giữ lại ngăn xếp cuộc gọi từ phương thức ném ngoại lệ xuống nơi khách hàng gọi nó. Thực tế có thể có những trường hợp sử dụng khi bạn sử dụng nó, nếu không thì những người tốt ở Microsoft sẽ không cho phép điều đó. Điều đó nói rằng, tôi đã không sử dụng nó. Một vấn đề khác cần nhớ là ném ngoại lệ là tốn kém. Chỉ làm điều đó vì một lý do rất chính đáng. Ghi nhật ký Tôi nghĩ sẽ hợp lý, v.v.
Charles Owen

5

Một điểm mà mọi người chưa đề cập là trong khi các ngôn ngữ .NET không thực sự phân biệt chính xác, câu hỏi liệu người ta nên hành động khi có ngoại lệ xảy ra hay không và liệu người ta có giải quyết được không, thực sự là những câu hỏi riêng biệt. Có nhiều trường hợp người ta phải hành động dựa trên ngoại lệ, người ta không có hy vọng giải quyết, và có một số trường hợp tất cả những gì cần thiết để "giải quyết" một ngoại lệ là giải phóng ngăn xếp đến một điểm nhất định - không cần phải thực hiện thêm hành động nào .

Bởi vì sự khôn ngoan thông thường mà người ta chỉ nên "bắt" những thứ mà người ta có thể "xử lý", rất nhiều mã sẽ hành động khi có ngoại lệ xảy ra, không. Ví dụ, rất nhiều mã sẽ thu được khóa, đưa đối tượng được bảo vệ "tạm thời" vào trạng thái vi phạm bất biến của nó, sau đó đưa đối tượng vào trạng thái hợp pháp và sau đó nhả khóa lại trước khi bất kỳ ai khác có thể nhìn thấy đối tượng. Nếu một ngoại lệ xảy ra trong khi đối tượng ở trạng thái không hợp lệ nguy hiểm, thực tế phổ biến là giải phóng khóa với đối tượng vẫn ở trạng thái đó. Một mô hình tốt hơn nhiều sẽ có một ngoại lệ xảy ra trong khi đối tượng ở trong tình trạng "nguy hiểm" rõ ràng vô hiệu hóa khóa, vì vậy mọi nỗ lực trong tương lai để có được nó sẽ ngay lập tức thất bại.

Trong hầu hết các ngôn ngữ .NET, cách duy nhất để mã thực hiện hành động dựa trên một ngoại lệ là catchnó (mặc dù nó biết rằng nó sẽ không giải quyết ngoại lệ), thực hiện hành động được đề cập và sau đó lại throw). Một cách tiếp cận khả thi khác nếu mã không quan tâm đến ngoại lệ nào được ném là sử dụng okcờ có try/finallykhối; đặt okcờ thành falsetrước khối và truetrước khi khối thoát ra và trước bất kỳ khối nào returntrong khối. Sau đó, bên trong finally, giả sử rằng nếu okkhông được đặt, một ngoại lệ phải xảy ra. Cách tiếp cận như vậy tốt hơn về mặt ngữ nghĩa so với a catch/ throw, nhưng xấu và ít được bảo trì hơn mức cần thiết.


5

Điều này có thể hữu ích khi chức năng lập trình của bạn cho một thư viện hoặc dll.

Cấu trúc suy nghĩ lại này có thể được sử dụng để thiết lập lại mục đích ngăn xếp cuộc gọi để thay vì nhìn thấy ngoại lệ được ném từ một hàm riêng lẻ bên trong hàm, bạn sẽ nhận được ngoại lệ từ chính hàm đó.

Tôi nghĩ rằng nó chỉ được sử dụng để các ngoại lệ được ném sạch hơn và không đi vào "gốc rễ" của thư viện.


3

Một lý do có thể để bắt-ném là vô hiệu hóa bất kỳ bộ lọc ngoại lệ nào sâu hơn ngăn xếp khỏi việc lọc xuống ( liên kết cũ ngẫu nhiên ). Nhưng tất nhiên, nếu đó là ý định, sẽ có một bình luận ở đó nói như vậy.


Tôi đã không hiểu bạn đang ở đâu cho đến khi tôi đọc liên kết ... và tôi vẫn không chắc chắn chính xác những gì bạn đang nói về ... tôi hoàn toàn không quen thuộc với VB.NET. Tôi nghĩ rằng nó dẫn đến tổng số được báo cáo là "không nhất quán", phải không? ... Tôi là một fan hâm mộ LỚN của các phương thức tĩnh .. ngoài việc chúng đơn giản, sẽ ít có sự không nhất quán nếu bạn tách biệt cài đặt các thuộc tính từ mã mà làm công việc thực tế. Các ngăn xếp là "tự làm sạch".
corlettk

3
Mọi người mong đợi rằng khi họ viết "thử {Foo ();} cuối cùng {Bar ();}" không có gì chạy giữa Foo và Bar. Nhưng điều này là không đúng sự thật; nếu người gọi của bạn đã thêm bộ lọc ngoại lệ và không có 'bắt' và Foo () ném, thì một số mã ngẫu nhiên khác từ người gọi của bạn sẽ chạy trước khi cuối cùng (Bar) của bạn chạy. Điều này rất tệ nếu bạn đã phá vỡ bất biến hoặc bảo mật nâng cao, hy vọng rằng chúng sẽ được 'khôi phục' ngay lập tức trở lại bình thường vào cuối cùng và không có mã nào khác sẽ thấy sự thay đổi tạm thời.
Brian

3

Nó phụ thuộc vào những gì bạn đang làm trong khối bắt và liệu bạn có muốn chuyển lỗi sang mã gọi hay không.

Bạn có thể nói Catch io.FileNotFoundExeption exvà sau đó sử dụng một đường dẫn tệp thay thế hoặc một số như vậy, nhưng vẫn gây ra lỗi.

Cũng làm Throwthay vì Throw Excho phép bạn giữ dấu vết ngăn xếp đầy đủ. Ném ex khởi động lại dấu vết ngăn xếp từ câu lệnh ném (tôi hy vọng điều đó có ý nghĩa).


3

Mặc dù nhiều câu trả lời khác cung cấp các ví dụ hay về lý do tại sao bạn có thể muốn bắt lại một ngoại lệ, nhưng dường như không ai đề cập đến một kịch bản 'cuối cùng'.

Một ví dụ về điều này là nơi bạn có một phương thức trong đó bạn đặt con trỏ (ví dụ: con trỏ chờ), phương thức này có một số điểm thoát (ví dụ: if () return;) và bạn muốn đảm bảo con trỏ được đặt lại tại kết thúc phương pháp.

Để làm điều này, bạn có thể bọc tất cả các mã trong một thử / bắt / cuối cùng. Cuối cùng, đặt con trỏ trở lại con trỏ bên phải. Vì vậy, bạn không chôn bất kỳ trường hợp ngoại lệ hợp lệ nào, hãy suy nghĩ lại về việc nắm bắt.

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}

1
catchmột phần bắt buộc của try...finallylịch sử, hay nó đóng một vai trò chức năng trong ví dụ này? - Tôi chỉ kiểm tra hai lần và tôi có thể sử dụng try {} finally {}mà không cần khối chặn.
Sebi

2

Trong ví dụ trong đoạn mã bạn đã đăng, trên thực tế, không có điểm nào bắt được ngoại lệ vì không có gì được thực hiện khi bắt nó, nó thực sự gây hại nhiều hơn là tốt khi ngăn xếp cuộc gọi bị mất .

Tuy nhiên, bạn sẽ bắt một ngoại lệ để thực hiện một số logic (ví dụ: đóng kết nối sql của khóa tệp hoặc chỉ ghi nhật ký) trong trường hợp ngoại lệ, hãy ném nó trở lại mã gọi để xử lý. Điều này sẽ phổ biến hơn trong một lớp nghiệp vụ so với mã giao diện người dùng vì bạn có thể muốn người viết mã triển khai lớp doanh nghiệp của bạn để xử lý ngoại lệ.

Để lặp lại mặc dù KHÔNG có điểm nào trong việc bắt ngoại lệ trong ví dụ bạn đã đăng. ĐỪNG làm như vậy!


1

Xin lỗi, nhưng nhiều ví dụ như "thiết kế cải tiến" vẫn có mùi khủng khiếp hoặc có thể cực kỳ sai lệch. Đã thử {} bắt {log; ném} là hoàn toàn vô nghĩa. Ghi nhật ký ngoại lệ nên được thực hiện ở vị trí trung tâm bên trong ứng dụng. ngoại lệ bong bóng stacktrace nào, tại sao không đăng nhập chúng ở đâu đó và gần với biên giới của hệ thống?

Cần thận trọng khi bạn tuần tự hóa ngữ cảnh của mình (ví dụ DTO trong một ví dụ cụ thể) chỉ vào thông điệp tường trình. Nó có thể dễ dàng chứa thông tin nhạy cảm mà người ta có thể không muốn đến tay tất cả những người có thể truy cập các tệp nhật ký. Và nếu bạn không thêm bất kỳ thông tin mới nào vào ngoại lệ, tôi thực sự không thấy điểm của gói ngoại lệ. Java cũ tốt có một số điểm cho điều đó, nó đòi hỏi người gọi phải biết loại ngoại lệ nào mà người ta mong đợi sau đó gọi mã. Vì bạn không có cái này trong .NET, nên việc gói không làm gì tốt với ít nhất 80% các trường hợp tôi đã thấy.


Cảm ơn bạn đã nghĩ Joe. Trong Java (và C #, tôi cho rằng) tôi rất thích thấy một chú thích cấp độ @FaultBoundary, điều này buộc TẤT CẢ các ngoại lệ (bao gồm các loại ngoại lệ không được kiểm tra) bị bắt hoặc bị tuyên bố là bị ném. Tôi sẽ sử dụng chú thích này trên các giao diện công cộng của mỗi lớp kiến ​​trúc. Vì vậy, giao diện @FaultBoundary ThingDAO sẽ không thể rò rỉ các chi tiết triển khai, chẳng hạn như SQLExceptions, NPE, hoặc AIOB. Thay vào đó, stacktrace "nhân quả" sẽ được ghi lại và DAOSystemException sẽ bị ném ... Tôi xác định ngoại lệ hệ thống là "gây tử vong vĩnh viễn".
corlettk

5
Có rất nhiều lý do để bắt, đăng nhập, sau đó suy nghĩ lại. Cụ thể nếu phương thức với nhật ký khai thác có thông tin bạn bị mất khi bạn ra khỏi phương thức. Lỗi có thể được xử lý sau nhưng không được ghi lại và bạn đã mất thông tin về các lỗi trong hệ thống.
Andy

1
Đây là nơi thuộc tính Dữ liệu của lớp Ngoại lệ tiện dụng - nắm bắt tất cả thông tin cục bộ đó để ghi nhật ký chung. Bài viết này ban đầu khiến tôi chú ý: blog.abodit.com/2010/03/ Khăn
McGuireV10

1

Ngoài những gì người khác đã nói, hãy xem câu trả lời của tôi cho một câu hỏi liên quan cho thấy rằng việc nắm bắt và suy nghĩ lại không phải là không có (nó có trong VB, nhưng một số mã có thể được gọi là C # từ VB).


Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
LHIOUI

@ HamzaLH, tôi đồng ý rằng đó không phải là một câu trả lời bằng văn bản, nhưng nó có thông tin, khác với các câu trả lời khác và phiếu bầu tích cực. Vì vậy, tôi không hiểu, tại sao bạn đề nghị xóa nó? Câu trả lời ngắn gọn về chủ đề và đưa ra giải pháp vẫn là câu trả lời. Từ meta.stackexchange.com/questions/226258/ấc
Michael Freidgeim

đây là câu trả lời chỉ liên kết
LHIOUI

1. Câu trả lời chỉ liên kết nên được thay đổi thành bình luận, không bị xóa. 2. Đây là một tài liệu tham khảo cho câu hỏi SO khác, không phải cho trang web bên ngoài, được coi là ít có khả năng bị phá vỡ theo thời gian. 3. Nó có một số mô tả bổ sung, khiến nó không phải là liên kết chỉ có mối quan hệ - xem meta.stackexchange.com/questions/225370/iêu
Michael Freidgeim

1

Hầu hết các câu trả lời nói về kịch bản bắt-log-rethrow.

Thay vì viết nó vào mã của bạn, hãy cân nhắc sử dụng AOP, đặc biệt là Postsharp.Diagnellect.Toolkit với OnExceptionOptions Bao gồmParameterValue và Bao gồmArArument


Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
Tony Dong

@TonyDong, tôi đồng ý rằng đó không phải là một câu trả lời tốt bằng văn bản, nhưng nó có thông tin, khác với các câu trả lời khác và phiếu bầu tích cực. Vì vậy, tôi không hiểu, tại sao bạn đề nghị xóa nó? BTW, liên kết 5 năm sau vẫn còn hiệu lực. Câu trả lời ngắn gọn về chủ đề và đưa ra giải pháp vẫn là câu trả lời. Từ meta.stackexchange.com/questions/226258/ấc
Michael Freidgeim

Stackoverflow chỉ có đề xuất này.
Tony Đồng

@TonyDong, nếu câu trả lời không hoàn toàn vô dụng, bạn nên chọn Cái Trông OK OK
Michael Freidgeim

0

Lấy lại các ngoại lệ thông qua throwrất hữu ích khi bạn không có một mã cụ thể để xử lý các ngoại lệ hiện tại hoặc trong trường hợp khi bạn có logic để xử lý các trường hợp lỗi cụ thể nhưng muốn bỏ qua tất cả các trường hợp khác.

Thí dụ:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Tuy nhiên, cũng có một cách khác để làm điều này, sử dụng mệnh đề có điều kiện trong các khối bắt:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Cơ chế này hiệu quả hơn so với ném lại một ngoại lệ vì thời gian chạy .NET không phải xây dựng lại đối tượng ngoại lệ trước khi ném lại.

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.