Khóa đã cho không có trong từ điển. Phím nào?


78

Có cách nào để lấy giá trị của khóa đã cho trong ngoại lệ sau trong C # theo cách ảnh hưởng đến tất cả các lớp chung không? Tôi nghĩ rằng đây là một thiếu sót lớn trong phần mô tả ngoại lệ từ Microsoft.

"The given key was not present in the dictionary."

Một cách tốt hơn sẽ là:

"The given key '" + key.ToString() + "' was not present in the dictionary."

Các giải pháp có thể liên quan đến mixin hoặc các lớp dẫn xuất.


13
Câu hỏi này có vẻ lạc đề bởi vì nó là một câu hỏi nói về việc triển khai một thông báo ngoại lệ, và không phải là một câu hỏi lập trình.
Servy

6
Vấn đề ở đây là trình gỡ lỗi không phải lúc nào cũng có sẵn, chẳng hạn như khi đọc tệp nhật ký.
Andreas

4
Bạn đang giả định rằng tất cả các từ điển đều có một khóa hợp .ToString()lý. Tôi đồng ý trong trường hợp a Dictionary<string, *>rằng nó sẽ là một bổ sung tuyệt vời cho mô tả ngoại lệ, nhưng nó không thể áp dụng cho tất cả các loại Dictionary<*,*>đối tượng.
Devilcodemonkey,

2
Không nhưng ngay cả khi key.ToString () đôi khi cho biết "Đối tượng" thì nó vẫn hoạt động trong 90% trường hợp.
Andreas

3
Tôi nghĩ một lý do khiến nó không có trong đó là MS hoàn toàn không biết chìa khóa là gì hoặc liệu nó có nên được tiết lộ hay không. Nó có thể là PII hoặc một bí mật không nên ghi lại. Hành vi an toàn hơn là để lộ ít chi tiết hơn khi bạn không biết ai sẽ xem chúng.
Mike Zboray

Câu trả lời:


73

Ngoại lệ này được đưa ra khi bạn cố gắng lập chỉ mục đến một thứ gì đó không có ở đó, ví dụ:

Dictionary<String, String> test = new Dictionary<String,String>();
test.Add("Key1,"Value1");
string error = test["Key2"];

Thông thường, một cái gì đó giống như một đồ vật sẽ là chìa khóa, điều này chắc chắn khiến nó khó lấy hơn. Tuy nhiên, bạn luôn có thể viết như sau (hoặc thậm chí gói gọn trong một phương thức mở rộng):

if (test.ContainsKey(myKey))
   return test[myKey];
else
   throw new Exception(String.Format("Key {0} was not found", myKey));

Hoặc hiệu quả hơn (nhờ @ScottChamberlain)

T retValue;
if (test.TryGetValue(myKey, out retValue))
    return retValue;
else
   throw new Exception(String.Format("Key {0} was not found", myKey));

Microsoft đã chọn không làm điều này, có lẽ vì nó sẽ vô dụng khi được sử dụng trên hầu hết các đối tượng. Nó đủ đơn giản để tự làm, vì vậy chỉ cần cuộn của riêng bạn!


19
Làm ContainsKeysau đó trình lập chỉ mục sẽ gây ra hai lần tra cứu trong từ điển. Thực hiện một TryGetValuesẽ chỉ là một lần tra cứu và bạn chỉ có thể sử dụng đầu ra Boolean của nó để chọn khối if / else của mình.
Scott Chamberlain

1
@ScottChamberlain Rất đúng. Đã thêm như một triển khai bổ sung.
BradleyDotNET

thử test.keys.contains (key) trả về boolean.
Kurkula

17

Trong trường hợp chung, câu trả lời là Không.

Tuy nhiên, bạn có thể đặt trình gỡ lỗi để ngắt tại điểm mà ngoại lệ được đưa ra đầu tiên. Tại thời điểm đó, khóa không có mặt sẽ có thể truy cập được dưới dạng giá trị trong ngăn xếp cuộc gọi.

Trong Visual Studio, tùy chọn này nằm ở đây:

Debug → Exceptions ... → Common Language Runtime Exceptions → System.Collections.Generic

Tại đó, bạn có thể chọn hộp Thrown .


Đối với các trường hợp cụ thể hơn trong đó thông tin cần thiết trong thời gian chạy, với điều kiện mã của bạn sử dụng IDictionary<TKey, TValue>và không bị ràng buộc trực tiếp Dictionary<TKey, TValue>, bạn có thể triển khai lớp từ điển của riêng mình để cung cấp hành vi này.


Đây thường là cách tôi chạy trình gỡ lỗi của mình.
AaronLS

Xin chào @Sam, bạn tìm thấy giá trị này tại thời điểm nào trong ngăn xếp cuộc gọi?
user919426

2
VS 2017 (v15.5.7) có nó như: Debug -> Windows -> Cài đặt ngoại lệ -> sau đó kiểm tra System.Collections.Generic.KeyNotFoundException
Robert Koch

9

Nếu bạn muốn quản lý các lỗi khóa, bạn nên sử dụng TryGetValue

https://msdn.microsoft.com/en-gb/library/bb347013(v=vs.110).aspx

string value = "";
if (openWith.TryGetValue("tif", out value))
{
    Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
    Console.WriteLine("Key = \"tif\" is not found.");
}

1
Điều này giả định rằng nó được sử dụng dự kiến ​​cho chìa khóa không ở đó. Đó có thể không phải là trường hợp. Nó có thể hợp pháp là một trường hợp ngoại lệ.
Servy

1
string Value = dic.ContainsKey("Name") ? dic["Name"] : "Required Name"

Với mã này, chúng tôi sẽ nhận được dữ liệu chuỗi trong 'Giá trị'. Nếu khóa 'Tên' tồn tại trong từ điển 'dic' thì tìm nạp giá trị này, còn lại trả về chuỗi "Tên bắt buộc".


2
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh liên quan đến lý do và / hoặc cách mã này trả lời câu hỏi sẽ cải thiện giá trị lâu dài của nó.
adiga

0

Bạn có thể thử mã này

Dictionary<string,string> AllFields = new Dictionary<string,string>();  
string value = (AllFields.TryGetValue(key, out index) ? AllFields[key] : null);

Nếu khóa không có, nó chỉ trả về giá trị null.

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.