2009-07-21 38 views
10

Tôi có nên kiểm tra xem khóa cụ thể có xuất hiện trong Từ điển không nếu tôi chắc chắn nó sẽ được thêm vào từ điển khi tôi truy cập mã để truy cập vào nó?Tôi có nên kiểm tra xem khóa cụ thể có trong Từ điển trước khi truy cập vào nó không?

Có hai cách tôi có thể truy cập vào các giá trị trong từ điển

  1. kiểm tra phương pháp containsKey. Nếu nó trả về true thì tôi truy cập bằng cách sử dụng indexer [key] của đối tượng dictionary.

hoặc

  1. TryGetValue đó sẽ trở lại đúng hay sai cũng như giá trị trả về thông qua tham số ra.

(2 sẽ hoạt động tốt hơn 1st nếu tôi muốn có được giá trị. Benchmark.)

Tuy nhiên nếu tôi chắc chắn rằng các chức năng mà được truy cập vào từ điển toàn cầu chắc chắn sẽ có chìa khóa rồi nên tôi vẫn kiểm tra sử dụng TryGetValue hoặc không kiểm tra, tôi nên sử dụng indexer [].

Hoặc tôi không bao giờ nên giả sử điều đó và luôn kiểm tra?

Trả lời

18

Sử dụng trình chỉ mục nếu khóa có nghĩa là có mặt - nếu không có, nó sẽ ném một ngoại lệ thích hợp, đó là hành vi đúng nếu không có phím cho biết lỗi.

Nếu nó hợp lệ cho khóa không có mặt, hãy sử dụng TryGetValue thay thế và phản ứng tương ứng.

(Cũng áp dụng lời khuyên của Marc về việc truy cập một cuốn từ điển chia sẻ một cách an toàn.)

+1

Phím bị thiếu thường là dấu hiệu của một vấn đề khác. Nếu bạn biết vấn đề là gì và có thể cung cấp một thông điệp hữu ích hơn, thì bạn nên cân nhắc việc ném ngoại lệ của riêng mình vì thông điệp kèm theo 'KeyNotFoundException' khó thu hẹp ở lần. –

+0

Nó chắc chắn sẽ hữu ích nếu KeyNotFoundException cũng đã cung cấp khóa - nhưng khác hơn thế, chỉ cần theo dõi stack thường đủ cho tôi. Làm thế nào đến nay bạn sẽ làm điều này: kiểm tra mọi tham chiếu null có thể (không chỉ đối số, nhưng những điều bạn nội bộ mong đợi là không null) cho nullity và ném một ngoại lệ tùy chỉnh trên mỗi một trong những? Sẽ luôn có trường hợp ngoại lệ được ném bởi các bit của khung trong trường hợp không thống nhất nội bộ: nếu bạn cố gắng dự đoán từng phần riêng lẻ, mã sẽ kết thúc bằng nhiều trường hợp lỗi hơn là tiến trình. –

10

Nếu từ điển là toàn cầu (tĩnh/chia sẻ), bạn nên đồng bộ hóa quyền truy cập vào nó (điều này rất quan trọng; nếu không bạn có thể làm hỏng nó).

Ngay cả khi chuỗi của bạn chỉ là đọc dữ liệu, nó cần phải tôn trọng khóa của các chủ đề khác có thể đang chỉnh sửa nó.

Tuy nhiên; nếu bạn chắc chắn rằng mục là có, indexer cần sử dụng tốt:

Foo foo; 
lock(syncLock) { 
    foo = data[key]; 
} 
// use foo... 

Nếu không, một mô hình hữu ích là để kiểm tra và bổ sung trong cùng khóa:

Foo foo; 
lock(syncLock) { 
    if(!data.TryGetValue(key, out foo)) { 
     foo = new Foo(key); 
     data.Add(key, foo); 
    } 
} 
// use foo... 

Ở đây chúng ta chỉ thêm mục nếu nó không có ở đó ... nhưng bên trong cùng một khóa.

+0

Tốt, nhưng tôi không nghĩ đó là câu hỏi? Tôi không thấy bất kỳ tham chiếu đến đồng thời? :) – Thorarin

+0

"từ điển toàn cầu" - chỉ cần đặt tôi xuống một đường dẫn nhất định. Nếu sự hiểu biết của tôi sai, OP có thể bỏ qua câu trả lời này ;-p –

+0

Tại sao chúng ta cần phải khóa khi đọc dữ liệu từ điển? Có phải do mở rộng từ điển/băm lại sau một số giới hạn? –

2

Luôn kiểm tra. Không bao giờ nói không bao giờ. Tôi cho rằng ứng dụng của bạn không phải là hiệu suất quan trọng mà bạn sẽ phải tiết kiệm thời gian kiểm tra.

CHỈ DẪN: Nếu bạn quyết định không kiểm tra, ít nhất hãy sử dụng Debug.Assert (dict.ContainsKey (khóa)); Điều này sẽ chỉ được biên dịch khi ở chế độ Gỡ lỗi, bản phát hành bản phát hành của bạn sẽ không chứa nó. Bằng cách đó bạn có thể ít nhất có kiểm tra khi gỡ lỗi.

Tuy nhiên: nếu có thể, chỉ cần kiểm tra xem nó :-)

EDIT: Đã có một số quan niệm sai lầm ở đây. Bởi "luôn luôn kiểm tra" Tôi không chỉ có nghĩa là sử dụng một nơi nào đó. Xử lý một ngoại lệ đúng cách cũng được bao gồm trong này. Vì vậy, để được chính xác hơn: không bao giờ mất bất cứ điều gì cho các cấp, mong đợi những bất ngờ. Kiểm tra bằng ContainsKey hoặc xử lý ngoại lệ tiềm năng, nhưng thực hiện SOMETHING trong trường hợp phần tử không được chứa.

+4

Tôi không đồng ý với điều này. Nếu chìa khóa có nghĩa là có mặt và không phải là, hành vi đúng là ném một ngoại lệ, phải không? Và đó chính xác là những gì mà người lập chỉ mục làm - vậy tại sao không sử dụng hành vi đó? Ngoài ra, tôi không quan tâm đến việc thay đổi hành vi giữa gỡ lỗi và phát hành bản dựng ... nó giống như một công thức cho các vấn đề với tôi. –

+0

Có, kiểm tra Gỡ lỗi không được dự định là phương pháp hay nhất. NHƯNG nó là tốt hơn so với không kiểm tra ở tất cả. Và ném một ngoại lệ nếu dữ liệu phải có trong từ điển chắc chắn là đúng cách để đi, nhưng sau đó nó có thể không phải là một ngoại lệ nội bộ từ điển, nhưng một trong đó tốt hơn phù hợp với vấn đề thực tế (e. G. InvalidOperationException). – galaktor

+0

Tôi đồng ý với Jon, bạn chỉ kiểm tra khi nào nó có thể hoặc có thể không có ở đó, nếu bạn chắc chắn rằng nó nên ở đó thì đường dẫn chính xác là cho phép ngoại lệ được ném và xử lý nó cho phù hợp. – James

0

TryGetValue là mã tương tự như lập chỉ mục nó bằng chìa khóa, ngoại trừ lợi nhuận cựu một giá trị mặc định (đối với tham số out), nơi ném sau một ngoại lệ. Sử dụng TryGetValue và bạn sẽ nhận được các kiểm tra nhất quán hoàn toàn không bị mất hiệu suất.

Chỉnh sửa: Như Jon đã nói, nếu bạn biết nó sẽ luôn có khóa, thì bạn có thể lập chỉ mục và để nó ném ngoại lệ thích hợp. Tuy nhiên, nếu bạn có thể cung cấp thông tin ngữ cảnh tốt hơn bằng cách tự ném thông tin bằng một thông báo chi tiết, điều đó sẽ thích hợp hơn.

0

Có 2 chuyến tàu được suy nghĩ về điều này từ quan điểm hiệu suất.

1) Tránh ngoại lệ nếu có thể, vì trường hợp ngoại lệ rất đắt - tức là kiểm tra trước khi bạn cố gắng truy xuất khóa cụ thể từ từ điển, cho dù có tồn tại hay không. Cách tiếp cận tốt hơn trong quan điểm của tôi nếu có một cơ hội công bằng nó có thể không tồn tại. Điều này sẽ ngăn chặn các ngoại lệ khá phổ biến.

2) Nếu bạn tin chắc mục đó sẽ tồn tại trong đó 99% thời gian, thì đừng kiểm tra sự tồn tại của nó trước khi truy cập. 1% thời gian khi nó không tồn tại, một ngoại lệ sẽ được ném nhưng bạn đã tiết kiệm thời gian cho 99% thời gian khác bằng cách không kiểm tra.

Điều tôi đang nói là, tối ưu hóa phần lớn nếu có hình ảnh rõ ràng. Nếu có bất kỳ mức độ không chắc chắn nào về một mục hiện có, thì hãy kiểm tra trước khi truy xuất.

+0

Tôi không nghĩ điều này thực sự là về hiệu suất. Nó phải là về tính chính xác: nếu khóa là * dự kiến ​​* sẽ ở đó trong các tình huống chính xác, tức là đó là lỗi cho khóa không ở đó, sau đó ném ngoại lệ là cách tiếp cận đúng để thất bại. Nếu không, bạn nên phát hiện tình huống * mà không * sử dụng ngoại lệ - xử lý các trường hợp ngoại lệ không có ngoại lệ là một ý tưởng tồi, IMO. –

+0

Tôi đang suy nghĩ nhiều hơn từ kịch bản mà nó không tồn tại trong từ điển sẽ không dẫn đến thất bại, ví dụ: nên sử dụng giá trị mặc định thay thế hoặc nên thêm giá trị vào nếu nó không tồn tại. Trường hợp nó nên tồn tại trong từ điển, nhưng nó không phải là một lỗi thực nếu nó không tồn tại - tức là giả sử từ điển là một bộ nhớ cache của một số dữ liệu từ một DB, nói rằng DB không có sẵn và bộ nhớ đệm không được điền, nhưng bạn không muốn điều đó gây ra lỗi trong hệ thống. Khó khăn để có được một ví dụ thực tế, vì vậy hy vọng tôi đang làm cho một số loại ý nghĩa! – AdaTheDev

0

Nếu bạn biết rằng từ điển này thường chứa khóa, bạn không phải kiểm tra trước khi truy cập.

Nếu có điều gì sai và từ điển không chứa các mục cần thiết, bạn có thể cho phép từ điển ném ngoại lệ. Lý do duy nhất để kiểm tra khóa đầu tiên sẽ là nếu bạn muốn tự chăm sóc cho vấn đề này mà không bị ngoại lệ. Để cho từ điển ném ngoại lệ và bắt đó là một cách hoàn toàn hợp lệ để xử lý tình huống.

0

Tôi nghĩ Marc và Jon có nó (như thường lệ) khá gieo. Vì bạn cũng đề cập đến hiệu suất trong câu hỏi của mình nên bạn nên cân nhắc cách khóa từ điển.

Đơn giản lock nối tiếp tất cả quyền truy cập đọc có thể không được mong muốn nếu đọc thường xuyên và ghi là tương đối ít. Trong trường hợp đó, sử dụng ReaderWriterLockSlim có thể tốt hơn. Nhược điểm là mã phức tạp hơn một chút và viết hơi chậm.

1

Cá nhân tôi muốn kiểm tra khóa là ở đó, bất kể bạn có chắc chắn là không, dù có thể nói séc này là thừa và từ điển sẽ ném một ngoại lệ mà bạn có thể bắt, nhưng bạn không nên dựa vào trên ngoại lệ đó, bạn nên kiểm tra bản thân và sau đó ném ngoại lệ của riêng bạn có nghĩa là một cái gì đó hoặc một đối tượng kết quả với cờ thành công và lý do bên trong ... cơ chế lỗi thực sự phụ thuộc vào việc thực hiện.

1

Chắc chắn câu trả lời là "tất cả đều phụ thuộc vào tình huống".Bạn cần cân bằng rủi ro mà khóa sẽ bị thiếu trong từ điển (thấp đối với các hệ thống nhỏ nơi có quyền truy cập hạn chế dữ liệu, nơi bạn có thể dựa vào thứ tự được thực hiện, lớn hơn cho các hệ thống lớn hơn, nhiều lập trình viên truy cập dữ liệu, đặc biệt là với truy cập đọc/ghi/xóa, trong đó các chủ đề liên quan và thứ tự không thể được đảm bảo hoặc dữ liệu bắt nguồn từ bên ngoài và đọc có thể bị lỗi) với tác động của rủi ro (hệ thống an toàn quan trọng, bản phát hành thương mại hoặc hệ thống mà doanh nghiệp sẽ dựa vào việc so sánh với thứ gì đó được tạo ra để giải trí, cho công việc một lần và/hoặc chỉ sử dụng) và với bất kỳ yêu cầu nào về tốc độ, kích thước và sự lười biếng.

Nếu tôi đang tạo hệ thống kiểm soát tín hiệu đường sắt, tôi muốn an toàn chống lại tất cả các lỗi có thể và không thể, và an toàn từ lỗi trong xử lý lỗi và vân vân (luật thứ 2 của Murphy: Nếu tôi đang chucking công cụ với nhau cho vui, ngay cả khi kích thước và tốc độ không phải là một vấn đề tôi sẽ được MUCH thoải mái hơn về những thứ như thế này - Tôi sẽ muốn để có được những thứ thú vị.

Tất nhiên, đôi khi đây là nội dung thú vị trong chính nó.

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