2008-08-11 15 views
6

Hãy tưởng tượng một đối tượng bạn đang làm việc có một bộ sưu tập các đối tượng khác được liên kết với nó, ví dụ như bộ sưu tập Điều khiển trên một WinForm. Bạn muốn kiểm tra một đối tượng nào đó trong bộ sưu tập, nhưng bộ sưu tập không có phương thức Contains(). Có một số cách để giải quyết vấn đề này.Sử dụng ngoại lệ không được xử lý thay vì Chứa()?

  • Thực hiện phương thức Contains() của riêng bạn bằng cách lặp qua tất cả các mục trong bộ sưu tập để xem liệu một trong số đó có phải là thứ bạn đang tìm kiếm hay không. Điều này có vẻ là phương pháp "thực hành tốt nhất".
  • Gần đây tôi đã xem qua một số mã nơi thay vì một vòng lặp, đã có một nỗ lực để truy cập vào các đối tượng bên trong một câu lệnh try, như sau:
try 
{ 
    Object aObject = myCollection[myObject]; 
} 
catch(Exception e) 
{ 
    //if this is thrown, then the object doesn't exist in the collection 
} 

Câu hỏi của tôi là như thế nào kém một thực hành lập trình để bạn xem xét lựa chọn thứ hai là và tại sao? Hiệu suất của nó so với một vòng lặp thông qua bộ sưu tập như thế nào?

Trả lời

2

Tôi sẽ phải nói rằng đây là thực tế khá tệ. Trong khi một số người có thể vui mừng nói rằng lặp qua bộ sưu tập thì kém hiệu quả hơn để ném một ngoại lệ, có một chi phí để ném một ngoại lệ. Tôi cũng sẽ hỏi tại sao bạn đang sử dụng một bộ sưu tập để truy cập một mục bằng khóa khi bạn sẽ phù hợp hơn với việc sử dụng từ điển hoặc có thể bắt đầu bằng.

Vấn đề chính của tôi với mã này tuy nhiên, là bất kể loại ngoại lệ được ném, bạn sẽ luôn bị bỏ lại với cùng một kết quả.

Ví dụ: một ngoại lệ có thể được ném vì đối tượng không tồn tại trong bộ sưu tập hoặc do chính bộ sưu tập đó là rỗng hoặc vì bạn không thể truyền myCollect [myObject] thành aObject.

Tất cả các trường hợp ngoại lệ này sẽ được xử lý theo cùng một cách, có thể không phải là ý định của bạn.

Đây là một vài điều tốt đẹp trên khi nào và nơi nó được usally coi là chấp nhận để ném ngoại lệ:

Tôi đặc biệt thích trích dẫn này từ bài viết thứ hai :

Điều quan trọng là ngoại lệ re chỉ được ném khi một hoạt động không mong muốn hoặc không hợp lệ xảy ra ngăn cản phương thức hoàn thành chức năng bình thường của nó. Xử lý ngoại lệ giới thiệu một chi phí nhỏ và chi phí thấp hơn hiệu suất vì vậy không nên được sử dụng cho luồng chương trình bình thường thay vì xử lý có điều kiện. Nó cũng có thể là khó duy trì mã mà lạm dụng xử lý ngoại lệ theo cách này.

0

Nếu, trong khi viết mã của bạn, bạn mong đợi đối tượng này nằm trong bộ sưu tập, và sau đó trong thời gian chạy bạn thấy rằng nó không phải là, tôi sẽ gọi đó là một trường hợp ngoại lệ, và nó là thích hợp để sử dụng một ngoại lệ.

Tuy nhiên, nếu bạn chỉ đơn giản là thử nghiệm cho sự tồn tại của một đối tượng, và bạn thấy rằng nó không có ở đó, điều này không phải là ngoại lệ. Sử dụng một ngoại lệ trong trường hợp này là không đúng.

Phân tích hiệu suất thời gian chạy phụ thuộc vào bộ sưu tập thực tế đang được sử dụng và phương pháp nếu tìm kiếm. Điều đó không thành vấn đề. Đừng để ảo tưởng về tối ưu hóa đánh lừa bạn vào viết mã khó hiểu.

-2

Giải pháp sau là giải pháp có thể chấp nhận được. Mặc dù tôi chắc chắn sẽ bắt được ngoại lệ cụ thể (ElementNotFound?) Mà bộ sưu tập được ném trong trường hợp đó.

Tốc độ nhanh, tùy thuộc vào trường hợp thông thường. Nếu bạn có nhiều khả năng tìm thấy phần tử hơn là không, giải pháp ngoại lệ sẽ nhanh hơn. Nếu bạn có nhiều khả năng thất bại, thì nó sẽ phụ thuộc vào kích thước của bộ sưu tập và tốc độ lặp lại của nó. Dù bằng cách nào, bạn cũng muốn đo lường việc sử dụng bình thường để xem đây có phải là cổ chai trước khi lo lắng về tốc độ như thế này không. Đi cho rõ ràng đầu tiên, và giải pháp thứ hai là xa rõ ràng hơn so với trước đây.

0

tôi sẽ phải suy nghĩ về nó nhiều hơn như để bao nhiêu tôi thích nó ... bản năng ruột của tôi là, eh, không quá nhiều ...

EDIT: ý kiến ​​của Ryan Fox vào trường hợp đặc biệt là hoàn hảo , Tôi đồng ý

Về hiệu suất, nó phụ thuộc vào chỉ mục trên bộ sưu tập. C# cho phép bạn ghi đè toán tử chỉ mục, vì vậy nếu nó đang thực hiện vòng lặp for giống như phương thức chứa, bạn sẽ viết, sau đó nó sẽ chậm (với một vài nano giây chậm hơn do try/catch ... nhưng không có gì để lo lắng về việc trừ khi mã đó nằm trong vòng lặp lớn).

Nếu chỉ mục là O (1) (hoặc thậm chí O (log (n)) ... hoặc bất kỳ thứ gì nhanh hơn O (n)), thì giải pháp try/catch sẽ nhanh hơn.

Ngoài ra, tôi giả định người lập chỉ mục đang ném ngoại lệ, nếu nó trả về null, bạn có thể chỉ cần kiểm tra null và không sử dụng try/catch.

0

Nói chung, việc sử dụng xử lý ngoại lệ cho luồng chương trình và logic là thực hành không tốt. Cá nhân tôi cảm thấy rằng tùy chọn thứ hai là việc sử dụng ngoại lệ không được chấp nhận. Do các tính năng của các ngôn ngữ thường được sử dụng trong những ngày này (chẳng hạn như LINQ và lambdas trong C# chẳng hạn), không có lý do gì để không viết phương thức Contains() của riêng bạn.

Như ý nghĩ cuối cùng, những ngày này hầu hết các bộ sưu tập do đều có phương pháp chứa. Vì vậy, tôi nghĩ rằng đối với hầu hết các phần này là một vấn đề không.

4

Quy tắc chung là tránh sử dụng ngoại lệ cho luồng kiểm soát trừ khi hoàn cảnh sẽ kích hoạt ngoại lệ là "ngoại lệ" - ví dụ: cực kỳ hiếm!

Nếu đây là điều gì đó sẽ xảy ra bình thường và thường xuyên, nó chắc chắn không nên được xử lý như một ngoại lệ.

Trường hợp ngoại lệ rất, rất chậm do tất cả chi phí liên quan, vì vậy cũng có thể có lý do hiệu suất, nếu điều đó xảy ra thường xuyên.

1

Trường hợp ngoại lệ phải là ngoại lệ.

Cái gì đó như 'Bộ sưu tập là mất tích vì cơ sở dữ liệu đã rơi ra từ bên dưới nó là đặc biệt

Cái gì đó như là chiếc chìa khóa là không có mặt "là hành vi bình thường đối với một cuốn từ điển.

Ví dụ cụ thể của bạn về một winforms Bộ sưu tập kiểm soát, thuộc tính Controls có phương thức ContainsKey, đó là những gì bạn được cho là sử dụng.

Không có ContainsValue vì khi xử lý từ điển/hashtables, không có cách nào nhanh chóng lặp lại toàn bộ bộ sưu tập, kiểm tra xem có gì đó không, vì vậy bạn thực sự chán nản khi làm điều đó.

Đối TẠI SAO Exceptions nên đặc biệt, đó là khoảng 2 điều

  1. Indicating gì mã của bạn đang cố gắng làm. Bạn muốn có mã của bạn phù hợp với những gì nó đang cố gắng để đạt được, càng chặt chẽ càng tốt, do đó, nó có thể đọc và duy trì. Xử lý ngoại lệ bổ sung thêm một loạt các hành trình bổ sung được thực hiện theo cách này

  2. Mức độ mã. Bạn muốn mã của bạn để làm những gì nó làm theo cách trực tiếp nhất, vì vậy nó có thể đọc được và duy trì được. Một lần nữa, các cruft thêm bởi xử lý ngoại lệ được trong cách này.

0

Hãy xem bài viết trên blog này từ Krzystof: http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx

Exceptions nên được sử dụng để giao tiếp điều kiện lỗi, nhưng họ không nên được sử dụng như điều khiển logic (đặc biệt là khi có nhiều cách đơn giản hơn nhiều để xác định một điều kiện, chẳng hạn như Chứa).

Một phần của vấn đề là ngoại lệ, trong khi không tốn kém đến ném rất tốn kém để bắt và tất cả các ngoại lệ đều bị bắt tại một số điểm.