1

I find the C# exceptions very annoying, because they provide so less information. What is the reason for this?

NullReferenceException or KeyNotFoundExceptions are hard to debug and sometimes you don´t get a linenumber in the stacktrace. Why can the exception itself not provide more informations?

For example:

private Dictionary<string, object> Properties = null;

public void Process(string key)
{ 
    var item = this.Properties[key];
    ....
}

When "Properties"is null I get a NullReferenceException:

"System.NullReferenceException: Object reference not set to an instance to an object"

Why I do not get:

"System.NullReferenceException: Object reference 'Properties' not set to an instance to an object"

This would be more usefull and the CLR does know, which reference is null.

The same when I pass a non existent key e.g. Process("dummy"):

"System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary"

Why I do not get:

"System.Collections.Generic.KeyNotFoundException: The key 'dummy' was not present in the dictionary"

The CLR knows, which key was passed and not found.

I try to debug such errors (which illegal keys are passed) in an productive environment and made the code more robust like:

private Dictionary<string, object> Properties = null;

public void Process(string key)
{ 
  if (this.Properties != null)
  {
    if (this.Properties.ContainsKey(key))
    {
        var item = this.Properties[key];
        ...
    }
    else
    {
        throw new KeyNotFoundException(string.Format("The key '{0}' was not found.", key));
    }
  }
  else
  {
    throw new NullReferenceException(string.Format("The object 'Properties' is null."));
  }
}

But why I have to do this, normally the CLR could tell me what was going wrong in detail. I cannot wrap all codepieces like this to get more informations when an exception happens.

4

5 回答 5

4

对于您KeyNotFoundException的 s,您可以创建自己的字典类来抛出更有意义的消息(我建议您尝试扩展KeyNotFoundException并抛出它),或者您可以使用TryGetValue并抛出一个有意义的异常。

然而NullReferenceException,一个要复杂得多:您假设 CLR 知道该事物被调用Properties,但它并不那么简单:考虑this.GetSomething(abc).DoSomething(),其中GetSomething(abc)返回 null。什么是空的对象?它没有名字。有时,特别是在发布优化的代码中,会生成变量名称或其他可能为空的东西。

您应该使用测试用例、Asserts、断点和其他调试模式代码进行调试,而不是期望您总是能获得足够好的异常消息来调试生产代码。例如,即使您知道密钥"dummy"已被传入,您也可能没有足够的信息来了解该密钥为何不正确或被传入。

于 2013-09-17T15:50:25.900 回答
1

通常,抛出异常的代码不知道要对消息做什么。从概念上讲,异常有可能同时包含Message和 一个DeveloperPrivateMessage属性,并指定异常应避免放置在Message任何向公众公开可能危及安全的信息中,并且接收异常的代码应避免DeveloperPrivateMessage以任何方式持续存在这会将其暴露给不受信任的人员,但这会使事情变得复杂。相反,抛出异常的代码应该简单地避免包含任何机密数据。由于字典无法知道密钥是否可用于存储机密数据,这意味着密钥不应包含在异常消息中。

至于,这通常被陷阱处理程序捕获,当寄存器为零时,NullReferenceException它可能能够确定代码正在尝试执行 a ,但陷阱处理程序无法知道 ESI 中的值来自哪里。如果说,并且该属性仅在修改后才返回,以便下一次调用不会返回 null,那么到系统尝试访问时,将不会为 null。系统可以做的最好的事情就是说“某个对象的成员为空”,但这可能不是很有帮助。mov eax,[esi+8]ESImeh = Foo.Bar.BoomBarnullFoonull.BoomFoo.BarBar

于 2013-09-18T18:08:18.317 回答
1

问题:为什么例外提供的信息比可用信息少?

答:可能的性能问题。

要产生好的KeyNotFoundException,你需要调用ToString()。这可能需要相当长的时间。例如,如果我 create Dictionary<StringBuilder, int>,找不到键将导致(可能是巨大的)新内存块被分配并填充数据(在 .NET 4.5 实现中)。此外,这可能导致异常消息包含几兆字节的文本。

问题:为什么不在 Debug 模式下使异常消息更详细?

答:不一致是不好的。

修复只能在发布模式下重现的错误非常困难。仅在调试模式下获取键的字符串表示会导致不同的行为:

  1. ToString可以抛出异常。

  2. 懒惰的程序员可以对异常消息进行检查。

问:但是有关于 UserVoice 的建议来改进消息。

答:如果你喜欢他们,就投他们一票。

NullReferenceException我想在链中有意义a.b.c.d.e.f.g.h()并不是首要任务。这很烦人,但它有一个简单的解决方法。如果你认为这是最重要的问题之一,那就去投票吧。但你可能会环顾四周,找到更多有趣的东西来投票。

于 2013-09-18T17:06:39.520 回答
0

然后您应该添加特殊处理以获取此信息。请记住,一切都是有代价的。您进行的异常处理越臃肿(首先不应该发生) - 对于这样的每个案例,框架就必须越大。

你真的应该考虑这些“最后机会例外”,因为如果编码正确,你永远不会看到它们。在异常消息和提供的堆栈跟踪之间 - 这对您来说应该是足够的信息。

于 2013-09-17T16:32:13.437 回答
0

检查 null 或是否缺少密钥的责任在于您,开发人员。原因是优化;如果默认异常像您希望的那样更详细,那么编译器将无法有效地优化。

这是一个权衡。添加空检查可能很烦人,但这就是语言的设计方式。

于 2013-09-17T16:42:00.410 回答