Thực hành tốt nhất để xử lý ngoại lệ trong ứng dụng Windows Forms?


118

Tôi hiện đang trong quá trình viết ứng dụng Windows Forms đầu tiên của mình. Bây giờ tôi đã đọc một vài cuốn sách về C # nên tôi đã hiểu tương đối tốt về những tính năng ngôn ngữ mà C # phải đối phó với các ngoại lệ. Tuy nhiên, tất cả chúng đều khá lý thuyết nên những gì tôi chưa có là cảm nhận về cách chuyển các khái niệm cơ bản thành một mô hình xử lý ngoại lệ tốt trong ứng dụng của tôi.

Có ai muốn chia sẻ bất kỳ viên ngọc trai nào của trí tuệ về chủ đề này không? Đăng bất kỳ lỗi phổ biến nào mà bạn đã thấy những người mới như tôi mắc phải và bất kỳ lời khuyên chung nào về việc xử lý các ngoại lệ theo cách giúp ứng dụng của tôi ổn định và mạnh mẽ hơn.

Những điều chính tôi hiện đang cố gắng giải quyết là:

  • Khi nào tôi nên ném lại một ngoại lệ?
  • Tôi có nên cố gắng có một cơ chế xử lý lỗi trung tâm nào đó không?
  • Việc xử lý các ngoại lệ có thể được đưa ra có ảnh hưởng đến hiệu suất so với việc kiểm tra trước những thứ như liệu tệp trên đĩa có tồn tại không?
  • Có nên đặt tất cả mã thực thi trong các khối try-catch-last không?
  • Có bất kỳ lúc nào khi khối bắt trống có thể được chấp nhận không?

Mọi lời khuyên đều nhận được một cách biết ơn!

Câu trả lời:


79

Một vài bit nữa ...

Bạn hoàn toàn nên có một chính sách xử lý ngoại lệ tập trung. Điều này có thể đơn giản như gói Main()trong một lần thử / bắt, không nhanh chóng với một thông báo lỗi duyên dáng cho người dùng. Đây là trình xử lý ngoại lệ "phương sách cuối cùng".

Kiểm tra trước luôn đúng nếu khả thi, nhưng không phải lúc nào cũng hoàn hảo. Ví dụ: giữa mã nơi bạn kiểm tra sự tồn tại của tệp và dòng tiếp theo nơi bạn mở tệp, tệp có thể đã bị xóa hoặc một số vấn đề khác có thể cản trở quyền truy cập của bạn. Bạn vẫn cần thử / bắt / cuối cùng trong thế giới đó. Sử dụng cả kiểm tra trước và thử / bắt / cuối cùng nếu thích hợp.

Không bao giờ "nuốt" một ngoại lệ, ngoại trừ trong những trường hợp được ghi chép đầy đủ nhất khi bạn hoàn toàn chắc chắn rằng ngoại lệ được ném ra là có thể tồn tại được. Điều này hầu như sẽ không bao giờ xảy ra. (Và nếu có, hãy đảm bảo rằng bạn chỉ nuốt một lớp ngoại lệ cụ thể - đừng bao giờ nuốtSystem.Exception .)

Khi xây dựng thư viện (được ứng dụng của bạn sử dụng), đừng nuốt các ngoại lệ và đừng ngại để các ngoại lệ nổi bong bóng. Đừng ném lại trừ khi bạn có thứ gì đó hữu ích để thêm vào. Đừng bao giờ (trong C #) làm điều này:

throw ex;

Vì bạn sẽ xóa ngăn xếp cuộc gọi. Nếu bạn phải ném lại (đôi khi cần thiết, chẳng hạn như khi sử dụng Khối Xử lý Ngoại lệ của Thư viện Doanh nghiệp), hãy sử dụng như sau:

throw;

Vào cuối ngày, phần lớn các ngoại lệ do một ứng dụng đang chạy ném ra sẽ bị lộ ra ở đâu đó. Chúng không nên được hiển thị cho người dùng cuối (vì chúng thường chứa dữ liệu độc quyền hoặc có giá trị khác), mà thường được ghi lại, với quản trị viên được thông báo về ngoại lệ. Người dùng có thể được hiển thị với một hộp thoại chung, có thể với một số tham chiếu, để giữ mọi thứ đơn giản.

Xử lý ngoại lệ trong .NET là nghệ thuật hơn là khoa học. Mọi người sẽ có mục yêu thích của họ để chia sẻ ở đây. Đây chỉ là một vài mẹo mà tôi đã chọn bằng cách sử dụng .NET kể từ ngày đầu tiên, các kỹ thuật đã giúp tôi tiết kiệm được nhiều hơn một lần. Số dặm của bạn có thể thay đổi.


1
Nếu một người để các ngoại lệ bong bóng, làm thế nào người gọi của một người có thể biết liệu ngoại lệ đó chỉ ra rằng một hoạt động không thành công nhưng hệ thống về cơ bản vẫn ổn (ví dụ: người dùng đã cố gắng mở một tệp tài liệu bị hỏng; tệp không tải, nhưng mọi thứ nếu không thì sẽ ổn), hoặc liệu nó có chỉ ra rằng CPU đang cháy và người ta nên đi đến các lối thoát càng nhanh càng tốt? Một cái gì đó như ArgumentException có thể chỉ ra một trong hai, tùy thuộc vào trường hợp mà nó được ném ra.
supercat

2
@supercat Bằng cách viết các lớp con cụ thể ApplicationExceptioncho những trường hợp lỗi mà ứng dụng sẽ có thể phân biệt và xử lý một cách hợp lý.
Matt Enright,

@Matt Enright: Chắc chắn là có thể bắt được các ngoại lệ của riêng mình, nhưng tôi không biết bất kỳ điều gì từ xa giống với một quy ước mà các mô-đun ném ngoại lệ cho biết liệu chúng có chỉ ra sự hỏng hóc của bất kỳ trạng thái nào bên ngoài ngoài những gì được ngụ ý bởi lỗi không. Lý tưởng nhất, một phương thức như SuperDocument.CreateFromFile () sẽ thành công, ném một ngoại lệ CleanFailure hoặc ném một SomethingReallyBadHappenedException. Thật không may, trừ khi một kết thúc tốt đẹp tất cả những gì có thể ném một ngoại lệ trong khối catch riêng của mình, không có cách nào để biết liệu một InvalidOperationException ...
supercat

@Matt Enright: ... nên được bao bọc trong CleanFailureException hoặc SomethingReallyBadHappenedException. Và gói mọi thứ trong các khối try-catch riêng lẻ sẽ đánh bại toàn bộ mục đích của việc có ngoại lệ ngay từ đầu.
supercat

2
Tôi nghĩ rằng đó là một thiết kế thư viện kém, để ẩn các chế độ lỗi với một loại ngoại lệ không chính xác. Đừng ném một FileNotFoundException nếu ý bạn thực sự là IOException hoặc InvalidDataException, vì ứng dụng cần phản hồi khác nhau cho từng trường hợp. Những thứ như StackOverflowException hoặc OutOfMemoryException không thể được xử lý một cách hợp lý bởi một ứng dụng, vì vậy hãy cứ để chúng nổi bong bóng, vì một ứng dụng hoạt động tốt luôn có trình xử lý tập trung "phương sách cuối cùng".
Matt Enright,

63

Có một bài viết CodeProject mã tuyệt vời ở đây . Dưới đây là một số điểm nổi bật:

  • Lập kế hoạch cho điều tồi tệ nhất *
  • Kiểm tra nó sớm
  • Không tin tưởng vào dữ liệu bên ngoài
  • Các thiết bị đáng tin cậy duy nhất là: video, chuột và bàn phím.
  • Viết cũng có thể thất bại
  • Mã an toàn
  • Đừng ném Exception mới ()
  • Không đặt thông tin ngoại lệ quan trọng trên trường Tin nhắn
  • Đặt một lần bắt duy nhất (Ngoại lệ ngoại lệ) cho mỗi luồng
  • Các trường hợp ngoại lệ chung bị bắt phải được xuất bản
  • Log Exception.ToString (); không bao giờ chỉ đăng nhập Exception.Message!
  • Không bắt (Ngoại lệ) nhiều hơn một lần cho mỗi chuỗi
  • Đừng bao giờ nuốt các ngoại lệ
  • Mã dọn dẹp nên được đặt trong các khối cuối cùng
  • Sử dụng "using" ở mọi nơi
  • Không trả lại các giá trị đặc biệt cho các điều kiện lỗi
  • Không sử dụng các trường hợp ngoại lệ để cho biết không có tài nguyên
  • Không sử dụng xử lý ngoại lệ làm phương tiện trả lại thông tin từ một phương thức
  • Sử dụng các ngoại lệ cho các lỗi không được bỏ qua
  • Không xóa dấu vết ngăn xếp khi ném lại một ngoại lệ
  • Tránh thay đổi ngoại lệ mà không thêm giá trị ngữ nghĩa
  • Các trường hợp ngoại lệ phải được đánh dấu [Có thể sắp xếp thứ tự]
  • Khi nghi ngờ, không Khẳng định, hãy ném Ngoại lệ
  • Mỗi lớp ngoại lệ phải có ít nhất ba hàm tạo ban đầu
  • Hãy cẩn thận khi sử dụng sự kiện AppDomain.UnhandledException
  • Đừng phát minh lại bánh xe
  • Không sử dụng Xử lý lỗi không có cấu trúc (VB.Net)

3
Bạn có vui lòng giải thích thêm một chút về điểm này cho tôi không? "Không sử dụng ngoại lệ để biểu thị sự thiếu vắng tài nguyên" Tôi không chắc mình hiểu lý do đằng sau nó. Cũng chỉ là một nhận xét: câu trả lời này không giải thích "tại sao" cả. Tôi biết điều này đã 5 tuổi nhưng nó vẫn làm tôi hơi khó chịu
Rémi

Liên kết đến bài viết được tham chiếu đã hết hạn. Code Project gợi ý rằng bài viết có thể đã chuyển đến đây .
DavidRR

15

Lưu ý rằng Windows Forms có cơ chế xử lý ngoại lệ riêng. Nếu một nút trong biểu mẫu được nhấp và trình xử lý của nó ném ra một ngoại lệ không bị bắt trong trình xử lý, Windows Forms sẽ hiển thị Hộp thoại Ngoại lệ Không được xử lý của chính nó.

Để ngăn Hộp thoại ngoại lệ không được xử lý hiển thị và bắt các ngoại lệ như vậy để ghi nhật ký và / hoặc để cung cấp hộp thoại lỗi của riêng bạn, bạn có thể đính kèm vào sự kiện Application.ThreadException trước khi gọi đến Application.Run () trong phương thức Main () của bạn.


Cảm ơn gợi ý này, tôi đã biết điều này quá muộn, tôi chỉ xác minh nó trong linqpad, hoạt động như mong đợi, đại biểu là: void Form1_UIThreadException (object sender, ThreadExceptionEventArgs t) Một nguồn tốt khác về chủ đề này là richnewman.wordpress.com/2007/ 04/08 /… Đối với việc xử lý ngoại lệ tổng thể không được xử lý: Sự kiện AppDomain.UnhandledException dành cho các trường hợp ngoại lệ không được xử lý được ném ra từ chuỗi giao diện người dùng không chính.
zhaorufei

14

Tất cả những lời khuyên được đăng ở đây cho đến nay đều tốt và đáng lưu tâm.

Một điều tôi muốn mở rộng thêm là câu hỏi của bạn "Việc xử lý các ngoại lệ có thể được đưa ra có ảnh hưởng đến hiệu suất so với việc kiểm tra trước những thứ như liệu tệp trên đĩa có tồn tại không?"

Quy tắc ngón tay cái ngây thơ là "khối thử / bắt rất đắt." Điều đó không thực sự đúng. Cố gắng không tốn kém. Đó là bắt, nơi hệ thống phải tạo một đối tượng Exception và tải nó lên với dấu vết ngăn xếp, điều đó rất tốn kém. Có nhiều trường hợp trong đó ngoại lệ, tốt, đủ đặc biệt đến mức hoàn toàn tốt để bọc mã trong một khối thử / bắt.

Ví dụ: nếu bạn đang điền một Từ điển, điều này:

try
{
   dict.Add(key, value);
}
catch(KeyException)
{
}

thường nhanh hơn làm điều này:

if (!dict.ContainsKey(key))
{
   dict.Add(key, value);
}

cho mọi mục bạn đang thêm, vì ngoại lệ chỉ được đưa ra khi bạn thêm một khóa trùng lặp. (Các truy vấn tổng hợp LINQ thực hiện điều này.)

Trong ví dụ bạn đưa ra, tôi sử dụng try / catch gần như không cần suy nghĩ. Đầu tiên, chỉ vì tệp tồn tại khi bạn kiểm tra nó không có nghĩa là tệp sẽ tồn tại khi bạn mở nó, vì vậy dù sao thì bạn cũng nên xử lý ngoại lệ.

Thứ hai, và tôi nghĩ quan trọng hơn, trừ khi a) quy trình của bạn đang mở hàng nghìn tệp và b) tỷ lệ một tệp mà nó đang cố mở không tồn tại không phải là thấp, hiệu suất của việc tạo ngoại lệ không phải là điều bạn có ' sẽ bao giờ để ý. Nói chung, khi chương trình của bạn đang cố gắng mở một tệp, nó chỉ đang cố gắng mở một tệp. Đó là trường hợp viết mã an toàn gần như chắc chắn sẽ tốt hơn viết mã nhanh nhất có thể.


3
trong trường hợp của dict, bạn chỉ có thể làm: dict[key] = valuephải nhanh hơn nếu không nhanh hơn ..
nawfal

9

Đây là một vài nguyên tắc mà tôi tuân theo

  1. Không nhanh: Đây là hướng dẫn tạo ngoại lệ nhiều hơn, Đối với mọi giả định mà bạn đưa ra và mọi tham số bạn đang nhận vào một hàm, hãy kiểm tra để đảm bảo rằng bạn đang bắt đầu với dữ liệu phù hợp và các giả định mà bạn đang làm là chính xác. Các kiểm tra điển hình bao gồm, đối số không rỗng, đối số trong phạm vi dự kiến, v.v.

  2. Khi ném lại, giữ nguyên dấu vết ngăn xếp - Điều này chỉ đơn giản là sử dụng ném khi ném lại thay vì ném Ngoại lệ () mới. Ngoài ra, nếu bạn cảm thấy rằng bạn có thể thêm nhiều thông tin hơn thì hãy bọc ngoại lệ ban đầu làm ngoại lệ bên trong. Nhưng nếu bạn đang bắt một ngoại lệ chỉ để ghi lại nó thì chắc chắn sử dụng ném;

  3. Đừng bắt các ngoại lệ mà bạn không thể xử lý, vì vậy đừng lo lắng về những thứ như OutOfMemoryException vì nếu chúng xảy ra, bạn sẽ không thể làm được gì nhiều.

  4. Thực hiện hook các trình xử lý ngoại lệ toàn cầu và đảm bảo ghi càng nhiều thông tin càng tốt. Đối với winforms, hãy móc cả tên miền ứng dụng và chuỗi sự kiện ngoại lệ không được xử lý.

  5. Hiệu suất chỉ nên được xem xét khi bạn đã phân tích mã và thấy rằng nó gây ra tắc nghẽn hiệu suất, theo mặc định, hãy tối ưu hóa cho khả năng đọc và thiết kế. Vì vậy, về câu hỏi ban đầu của bạn về việc kiểm tra sự tồn tại của tệp, tôi sẽ nói điều đó tùy thuộc vào, Nếu bạn có thể làm điều gì đó về việc tệp không ở đó, thì có, hãy kiểm tra ngược lại nếu tất cả những gì bạn sẽ làm là ném một ngoại lệ nếu tệp của không có thì tôi không thấy điểm.

  6. Chắc chắn có những lúc yêu cầu các khối bắt trống, tôi nghĩ những người nói khác đã không làm việc trên các cơ sở mã đã phát triển qua nhiều bản phát hành. Nhưng chúng nên được nhận xét và xem xét để đảm bảo rằng chúng thực sự cần thiết. Ví dụ điển hình nhất là các nhà phát triển sử dụng try / catch để chuyển chuỗi thành số nguyên thay vì sử dụng ParseInt ().

  7. Nếu bạn mong đợi người gọi mã của mình có thể xử lý các điều kiện lỗi thì hãy tạo các ngoại lệ tùy chỉnh nêu chi tiết tình huống không được kiểm tra là gì và cung cấp thông tin có liên quan. Nếu không, chỉ cần sử dụng các loại ngoại lệ được tích hợp sẵn càng nhiều càng tốt.


Việc sử dụng trong việc nối cả miền ứng dụng và trình xử lý ngoại lệ chưa xử lý chuỗi chưa xử lý là gì? Nếu bạn chỉ sử dụng Appdomain.UnhandledException, đó không phải là cái chung nhất sẽ bắt được mọi thứ sao?
Đầm lầy

Ý của bạn là xử lý Application.ThreadExceptionsự kiện khi bạn tham chiếu đến sự kiện "ngoại lệ không được xử lý chuỗi"?
Jeff B,

4

Tôi thích triết lý không bắt bất cứ thứ gì mà tôi không có ý định xử lý, bất kỳ việc xử lý nào có nghĩa là trong bối cảnh cụ thể của tôi.

Tôi ghét nó khi tôi nhìn thấy mã như:

try
{
   // some stuff is done here
}
catch
{
}

Tôi đã thấy điều này thỉnh thoảng và khá khó để tìm ra vấn đề khi ai đó 'ăn' các ngoại lệ. Một đồng nghiệp của tôi đã làm điều này và nó có xu hướng trở thành người đóng góp vào một dòng vấn đề ổn định.

Tôi ném lại nếu có điều gì đó mà lớp cụ thể của tôi cần phải làm để đáp ứng với một ngoại lệ nhưng vấn đề cần được giải thích để tuy nhiên được gọi là phương thức nơi nó đã xảy ra.

Tôi nghĩ rằng mã nên được viết một cách chủ động và các ngoại lệ phải dành cho các tình huống đặc biệt, không phải để tránh việc kiểm tra các điều kiện.


@Kiquenet Xin lỗi, tôi hơi không rõ ràng. Ý tôi là: Đừng thực hiện những thao tác bắt trống như vậy, thay vào đó hãy thêm một trình xử lý vào Dispatcher . vào thiết kế của bạn. Hãy ném chúng khi chúng cần ném, lập hợp đồng rõ ràng cho bạn Giao diện / API / bất kỳ Lớp nào.
LuckyLikey

4

Tôi đang trên đường ra ngoài nhưng sẽ cung cấp cho bạn một bản sơ lược về nơi sử dụng xử lý ngoại lệ. Tôi sẽ cố gắng giải quyết các điểm khác của bạn khi tôi trở lại :)

  1. Kiểm tra rõ ràng tất cả các điều kiện lỗi đã biết *
  2. Thêm thử / nắm bắt xung quanh mã nếu bạn không chắc chắn liệu bạn có thể xử lý tất cả các trường hợp không
  3. Thêm một thử / bắt xung quanh mã nếu giao diện .NET bạn đang gọi ném ra một ngoại lệ
  4. Thêm thử / nắm bắt xung quanh mã nếu nó vượt qua ngưỡng phức tạp đối với bạn
  5. Thêm thử / nắm bắt xung quanh mã nếu để kiểm tra sự tỉnh táo: Bạn đang khẳng định ĐIỀU NÀY KHÔNG BAO GIỜ XẢY RA
  6. Theo nguyên tắc chung, tôi không sử dụng ngoại lệ để thay thế cho mã trả lại. Điều này là tốt cho .NET, nhưng không phải với tôi. Tuy nhiên, tôi cũng có ngoại lệ (hehe) đối với quy tắc này, nó phụ thuộc vào kiến ​​trúc của ứng dụng bạn đang làm việc.

*Trong vòng suy luận. Không cần phải kiểm tra xem liệu một tia vũ trụ chiếu vào dữ liệu của bạn có khiến một vài bit bị lật hay không. Hiểu thế nào là "hợp lý" là một kỹ năng cần có đối với một kỹ sư. Thật khó để định lượng, nhưng lại rất dễ dàng. Đó là, tôi có thể dễ dàng giải thích lý do tại sao tôi sử dụng try / catch trong bất kỳ trường hợp cụ thể nào, nhưng tôi lại khó thấm nhuần kiến ​​thức khác với cùng kiến ​​thức này.

Tôi cho một người có xu hướng tránh xa các kiến ​​trúc dựa trên ngoại lệ. try / catch không có lần truy cập hiệu suất như vậy, lần truy cập xuất hiện khi ngoại lệ được ném ra và mã có thể phải đi lên một số cấp của ngăn xếp lệnh gọi trước khi thứ gì đó xử lý nó.


4

Quy tắc vàng đã cố gắng tuân theo là xử lý ngoại lệ càng gần nguồn càng tốt.

Nếu bạn phải ném lại một ngoại lệ, hãy cố gắng thêm vào nó, việc ném lại một FileNotFoundException không giúp được gì nhiều nhưng việc ném một ConfigurationFileNotFoundException sẽ cho phép nó bị bắt và hoạt động ở đâu đó trong chuỗi.

Một quy tắc khác mà tôi cố gắng tuân theo là không sử dụng try / catch như một dạng dòng chương trình, vì vậy tôi xác minh các tệp / kết nối, đảm bảo các đối tượng đã được khởi tạo, v.v. trước khi sử dụng chúng. Thử / bắt nên dành cho Ngoại lệ, những thứ bạn không thể kiểm soát.

Đối với một khối bắt trống, nếu bạn đang làm bất kỳ điều gì quan trọng trong mã tạo ra ngoại lệ, bạn nên ném lại ngoại lệ ở mức tối thiểu. Nếu không có hậu quả của mã đã ném ngoại lệ không chạy tại sao bạn lại viết nó ngay từ đầu.


"Quy tắc vàng" này tốt nhất là tùy ý.
Evan Harper

3

bạn có thể bẫy sự kiện ThreadException.

  1. Chọn một dự án Ứng dụng Windows trong Giải pháp Explorer.

  2. Mở tệp Program.cs đã tạo bằng cách nhấp đúp vào tệp.

  3. Thêm dòng mã sau vào đầu tệp mã:

    using System.Threading;
  4. Trong phương thức Main (), hãy thêm dòng sau vào dòng đầu tiên của phương thức:

    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
  5. Thêm phần sau vào bên dưới phương thức Main ():

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        // Do logging or whatever here
        Application.Exit();
    }
  6. Thêm mã để xử lý ngoại lệ chưa xử lý trong trình xử lý sự kiện. Bất kỳ ngoại lệ nào không được xử lý ở bất kỳ nơi nào khác trong ứng dụng đều được xử lý bằng mã trên. Thông thường nhất, mã này sẽ ghi lại lỗi và hiển thị thông báo cho người dùng.

refrence: https://blogs.msmvps.com/deborahk/global-exception-handler-winforms/


@Kiquenet xin lỗi, tôi không biết về VB
Omid-RH

2

Ngoại lệ là tốn kém nhưng cần thiết. Bạn không cần phải gói gọn mọi thứ trong một lần thử bắt nhưng bạn cần đảm bảo rằng các trường hợp ngoại lệ luôn được nắm bắt cuối cùng. Phần lớn nó sẽ phụ thuộc vào thiết kế của bạn.

Đừng ném lại nếu để ngoại lệ tăng lên cũng sẽ làm được. Đừng bao giờ để lỗi trôi qua không được chú ý.

thí dụ:

void Main()
{
  try {
    DoStuff();
  }
  catch(Exception ex) {
    LogStuff(ex.ToString());
  }

void DoStuff() {
... Stuff ...
}

Nếu DoStuff gặp sự cố, bạn vẫn muốn nó được bảo lãnh. Ngoại lệ sẽ được đưa lên chính và bạn sẽ thấy nhóm sự kiện trong dấu vết ngăn xếp của người cũ.


1

Khi nào tôi nên ném lại một ngoại lệ?

Mọi nơi, nhưng phương pháp người dùng cuối ... như trình xử lý nhấp vào nút

Tôi có nên cố gắng có một cơ chế xử lý lỗi trung tâm nào đó không?

Tôi viết một tệp nhật ký ... khá dễ dàng cho một ứng dụng WinForm

Việc xử lý các ngoại lệ có thể được đưa ra có ảnh hưởng đến hiệu suất so với việc kiểm tra trước những thứ như liệu tệp trên đĩa có tồn tại không?

Tôi không chắc về điều này, nhưng tôi tin rằng đó là một phương pháp hay để tìm các ngoại lệ ... Ý tôi là bạn có thể hỏi liệu một tệp có tồn tại hay không và nếu nó không ném ra một FileNotFoundException

Có nên đặt tất cả mã thực thi trong các khối try-catch-last không?

yeap

Có bất kỳ lúc nào khi khối bắt trống có thể được chấp nhận không?

Có, giả sử bạn muốn hiển thị một ngày, nhưng bạn không biết ngày đó được lưu trữ như thế nào (dd / mm / yyyy, mm / dd / yyyy, v.v.) bạn thử phân tích cú pháp tp nhưng nếu nó không thành công, hãy tiếp tục .. . nếu nó không liên quan đến bạn ... tôi sẽ nói có, có


1

Một điều tôi học được rất nhanh là bao gồm tuyệt đối mọi đoạn mã tương tác với bất kỳ thứ gì bên ngoài luồng chương trình của tôi (tức là Hệ thống tệp, Lệnh gọi cơ sở dữ liệu, Đầu vào của người dùng) bằng các khối thử bắt. Việc thử bắt có thể phải chịu một lần truy cập hiệu suất, nhưng thường ở những vị trí này trong mã của bạn, nó sẽ không đáng chú ý và nó sẽ tự trả giá bằng sự an toàn. thực sự cần phải đăng một tin nhắn nhưng nếu bạn không nắm bắt được nó, nó sẽ tạo ra một lỗi ngoại lệ không được xử lý cho người dùng.

Tôi đã sử dụng các khối bắt trống ở những nơi mà người dùng có thể làm điều gì đó không thực sự "không chính xác", nhưng nó có thể tạo ra một ngoại lệ ... một ví dụ mà tôi nghĩ đến là trong GridView nếu người dùng DoubleCLicks trình giữ chỗ màu xám ô ở trên cùng bên trái nó sẽ kích hoạt sự kiện CellDoubleClick, nhưng ô không thuộc một hàng. Trong trường hợp đó, bạn không


1

Khi ném lại một ngoại lệ, từ khóa do nó tự ném ra. Thao tác này sẽ loại bỏ ngoại lệ bị bắt và vẫn có thể sử dụng dấu vết ngăn xếp để xem nó đến từ đâu.

Try
{
int a = 10 / 0;
}
catch(exception e){
//error logging
throw;
}

làm điều này sẽ làm cho dấu vết ngăn xếp kết thúc trong câu lệnh catch. (tránh điều này)

catch(Exception e)
// logging
throw e;
}

điều này có còn áp dụng cho các phiên bản .NET Framework và .NET Core mới nhất không?
LuckyLikey,

1

n kinh nghiệm của tôi mà tôi thấy phù hợp để nắm bắt các trường hợp ngoại lệ khi tôi biết mình sẽ tạo ra chúng. Đối với các trường hợp khi tôi đang ở trong một ứng dụng web và tôi đang thực hiện Response.Redirect, tôi biết mình sẽ nhận được một System.ThreadAbortException. Vì đó là chủ ý nên tôi chỉ bắt được một loại cụ thể và chỉ cần nuốt nó.

try
{
/*Doing stuff that may cause an exception*/
Response.Redirect("http:\\www.somewhereelse.com");
}
catch (ThreadAbortException tex){/*Ignore*/}
catch (Exception ex){/*HandleException*/}

1

Tôi đồng ý sâu sắc quy tắc:

  • Đừng bao giờ để lỗi trôi qua không được chú ý.

Lý do là:

  • Khi bạn viết mã lần đầu tiên, rất có thể bạn sẽ không có kiến ​​thức đầy đủ về mã 3 bên, danh dự .NET FCL hoặc những đóng góp mới nhất của đồng nghiệp. Trong thực tế, bạn không thể từ chối viết mã cho đến khi bạn biết rõ mọi khả năng ngoại lệ. Vì thế
  • Tôi thường thấy rằng tôi sử dụng try / catch (Exception ex) chỉ vì tôi muốn bảo vệ bản thân khỏi những thứ không xác định và, như bạn nhận thấy, tôi bắt Exception, không phải cụ thể hơn như OutOfMemoryException, v.v. Và, tôi luôn đặt ngoại lệ được đưa ra cho tôi (hoặc QA) bởi ForceAssert.AlwaysAssert (false, ex.ToString ());

ForceAssert.AlwaysAssert là cách Trace.Assert cá nhân của tôi bất kể macro DEBUG / TRACE có được xác định hay không.

Chu kỳ phát triển có thể: Tôi nhận thấy hộp thoại Assert xấu xí hoặc ai đó khác phàn nàn với tôi về nó, sau đó tôi quay lại mã và tìm ra lý do để tăng ngoại lệ và quyết định cách xử lý nó.

Bằng cách này tôi có thể viết ra TÔI mã trong thời gian ngắn và bảo vệ tôi khỏi miền không xác định, nhưng luôn bị chú ý nếu điều bất thường xảy ra, bằng cách này, hệ thống trở nên an toàn và an toàn hơn.

Tôi biết nhiều người trong số các bạn sẽ không đồng ý với tôi bởi vì một nhà phát triển nên biết mọi chi tiết về mã của họ, thành thật mà nói, ngày xưa tôi cũng là một người theo chủ nghĩa thuần túy. Nhưng bây giờ tôi mới biết rằng chính sách trên thực dụng hơn.

Đối với mã WinForms, một quy tắc vàng mà tôi luôn tuân theo là:

  • Luôn thử / bắt (Ngoại lệ) mã xử lý sự kiện của bạn

điều này sẽ bảo vệ giao diện người dùng của bạn luôn có thể sử dụng được.

Đối với lượt truy cập hiệu suất, hình phạt hiệu suất chỉ xảy ra khi mã tiếp cận bắt được, việc thực thi mã thử mà không có ngoại lệ thực sự được nêu ra không có ảnh hưởng đáng kể.

Ngoại lệ nên xảy ra với rất ít cơ hội, nếu không thì không phải là ngoại lệ.


-1

Bạn phải nghĩ về người dùng. Sự cố ứng dụng là lần cuối cùngthứ mà người dùng muốn. Do đó, bất kỳ hoạt động nào có thể thất bại đều phải có khối try catch ở cấp ui. Không cần thiết phải sử dụng try catch trong mọi phương thức, nhưng mỗi khi người dùng làm điều gì đó, nó phải có khả năng xử lý các ngoại lệ chung. Điều đó không có nghĩa là giải phóng bạn khỏi việc kiểm tra mọi thứ để ngăn ngừa ngoại lệ trong trường hợp đầu tiên, nhưng không có ứng dụng phức tạp nào không có lỗi và hệ điều hành có thể dễ dàng thêm các sự cố không mong muốn, do đó bạn phải lường trước điều không mong muốn và đảm bảo nếu người dùng muốn sử dụng hoạt động sẽ không bị mất dữ liệu vì ứng dụng bị treo. Không cần thiết phải để ứng dụng của bạn gặp sự cố, nếu bạn nắm bắt được các trường hợp ngoại lệ, nó sẽ không bao giờ ở trạng thái không xác định và người dùng LUÔN LUÔN gặp bất tiện khi gặp sự cố. Ngay cả khi ngoại lệ ở cấp cao nhất, không bị treo có nghĩa là người dùng có thể nhanh chóng tạo lại ngoại lệ hoặc ít nhất là ghi lại thông báo lỗi và do đó giúp bạn rất nhiều để khắc phục sự cố. Chắc chắn hơn rất nhiều so với việc nhận được một thông báo lỗi đơn giản và sau đó chỉ thấy hộp thoại lỗi cửa sổ hoặc một cái gì đó tương tự.

Đó là lý do tại sao bạn KHÔNG BAO GIỜ được tự phụ và nghĩ rằng ứng dụng của bạn không có lỗi, điều đó không được đảm bảo. Và đó là một nỗ lực rất nhỏ để gói một số khối thử bắt về mã thích hợp và hiển thị thông báo lỗi / ghi lại lỗi.

Là một người dùng, tôi chắc chắn rất khó chịu bất cứ khi nào một ứng dụng văn phòng hoặc ứng dụng duyệt web hoặc bất cứ thứ gì gặp sự cố. Nếu trường hợp ngoại lệ quá cao khiến ứng dụng không thể tiếp tục thì tốt hơn là hiển thị thông báo đó và cho người dùng biết phải làm gì (khởi động lại, sửa một số cài đặt hệ điều hành, báo cáo lỗi, v.v.) hơn là chỉ đơn giản là gặp sự cố và thế là xong.


Bạn có thể cố gắng viết các câu trả lời ít giống như một lời tuyên bố và thay vào đó cố gắng cụ thể hơn và cố gắng chứng minh quan điểm của bạn? Ngoài ra, hãy xem Cách trả lời .
LuckyLikey
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.