KeyNotFoundException信息

我有一个C#Silverlight应用程序,它随机抛出一个“ KeyNotFoundException ”。 我不知道找不到什么钥匙。 这引出了两个问题:

  1. KeyNotFoundException是否存储/公开它试图找到的键? 当我查看文档时 ,我没有看到任何暗示此信息可用的内容。
  2. 我在一般的Application.UnhandledException事件处理程序中捕获/记录此exception。 我的问题是,如果我在这里捕获事件,我可以将ExceptionObject转换为KeyNotFoundException,并且如果它在#1中被询问,它仍然会获得关键信息吗?

非常感谢你的帮助!

KeyNotFoundException是由于当键不存在时尝试使用给定键从字典中获取值而引起的。 例如:

 var dictionary = new Dictionary(); var val = dictionary["mykey"]; 

您可以查看使用字典的所有位置并确定自己。 一般的最佳实践是,如果您在字典中查找可能不存在的值,则使用TryGetValue 。 每次捕获exception都是一项更昂贵的操作,并且是不必要的:

 string val; if(dictionary.TryGetValue("mykey", out val)) { //The key was found. The value is in val. } else { //The key was not present. } 

您可以查看KeyNotFoundExceptionStackTrace属性,以确定问题的确切位置。 所有exception都具有StackTrace属性,因此您无需关心它在全局error handling程序中的exception类型。 例如:

 private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { var stackTrace = e.ExceptionObject.StackTrace; //Log the stackTrace somewhere. } 

或者,如果您希望能够告诉它是什么类型的exception:

 private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (e.ExceptionObject is KeyNotFoundException) { //This was a KeyNotFoundException } } 

当字典抛出KeyNotFoundException ,它不会尝试告诉您它试图找到哪个键。 因此,我经常尝试在我的词典上使用扩展方法,这样如果我的程序中断,我知道它试图查找的键。 虽然知道堆栈跟踪是有用的,但通常是不够的,特别是如果查找发生在循环内。

 public static TValue GetOrThrow(this IDictionary d, TKey key) { try { return d[key]; } catch(KeyNotFoundException ex) { throw new KeyNotFoundException(key.ToString() + " was not found in the dictionary"); } } 

更新/澄清

我实际上并没有调用key.ToString()因为它可能是一个不覆盖ToString() 。 默认情况下将打印类型名称: "MyLibrary.SomeType was not found.""{ managerId: 123, employeeId: 456} was not found."那么有用"{ managerId: 123, employeeId: 456} was not found."

所以相反,我将它序列化为json,就像这样:

 var serializedKey = Newtonsoft.Json.JsonConvert.SerializeObject( key, new JsonSerializerSettings { //make it easy for humans to read Formatting = Formatting.Indented, //don't break on loops...that would cause a new error that hides the KeyNotFound! ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); 

此外,我发现将特定键值放在exception消息中会使得很难在日志中聚合exception,具体取决于您使用的工具类型。 (我正在使用一个通过外部exception消息对错误进行分组的方法 )。 如果这会影响您,您可能希望将详细信息放在内部exception中:
throw new KeyNotFoundException( "key was not found", new KeyNotFoundException(serializedKey));

我认为找到问题的最佳方法是在Application.UnhandledException方法中记录给定exception的StackTrace。 通过StackTrace,您可以找到问题的根源(方法的名称,导致exception的文件的名称和行)。 这样,您就可以了解代码的错误。 总是尝试尽可能多地记录。

这是因为windows phone的silverlight不支持wsHttpBinding,所以你将服务改为basicHttpBinding,它会工作