什么时候抛出InvalidOperationException?

时间:2012-02-27 14:52:16

标签: .net exception throw invalidoperationexception

我想我知道我的意思但我不太确定......

框架文档总结了如下类型:

  

当方法调用对象的当前状态无效时引发的异常。

有明确的案例,想到的是一个操作需要一个开放的数据库,但该对象尚未初始化所需的信息以连接到数据库。

(Tangent:另一方面也要求你明确打开连接的ADO.NETs行为并不是那么明确; DataAdapter通过简单地打开连接instad而不同于此,当且仅当它关闭时,它再次关闭它在入口处关闭了,我觉得这很方便,并且自己做了一个ADO.NET包装器,它使用了这个模式。当然这意味着我冒险做2个ExecuteNonQuery并且不必要地将连接返回到池之间,但我仍然可以在我想要的时候打开和关闭连接,与获得异常相比,这种性能损失是无效的。)

我想我的问题的答案是,只有在如此明确的情况下,我们才应该抛出异常。但在以下场景中哪种异常类型最合适:

public class FormatterMapping
{
  Dictionary formattersByName = new ...();

  public IFormatter GetFormatter(string key) 
  {
     IFormatter f;
     if (formattersByName.TryGetValue(key, out f)) 
       return f;
     else
       throw new ??Exception("explanation of why this failed.");
  }
}

我的第一直觉是抛出ArgumentException。然后我开始认为,由于参数“错误”,映射缺少一个键也可能。基本上“获取格式化程序X”操作无效因为 X不在映射中,但我真的不知道X“是否应该在那里”或者要求它是不明智的X在这里。

我当然可以通过返回null来绕过整个问题,但这会打开更大,更深的蠕虫。没有办法知道何时使用返回值,因此稍后用NullReferenceException抛出的代码可能与出错的地方没有明显的关系。要么映射设置不当,要么使用它的代码要求它不应该。

避免这个问题的另一种方法是前往TryGetFormatter选项,但我打算使用它的方式实际上应该知道调用者是什么和不在映射中,所以强迫用户使用这种模式代码也不好。

请不要回答我应该抛出ApplicationException!无论您认为代码应该做什么,请提供原因。毕竟这是在这里真正存在问题的推理。

除非有人说服我,否则我倾向于ArgumentException。从映射的角度来看,论证是错误的,所以至少有一条明确的推理线支持这一点。 :)

2 个答案:

答案 0 :(得分:4)

两者都不完美,两者都没问题。或许你想要一些真正明确的东西:

KeyNotFoundException

public class FormatterMapping
{
    Dictionary<string, IFormatter> formattersByName = new ...();

    public IFormatter GetFormatter(string key) 
    {
        // validate the argument
        if (!formattersByName.ContainsKey(key))
            throw new KeyNotFoundException("No formatter exists for given key");

        return formattersByName[key];
    }
}

或者你可以让Dictionary&lt;&gt;抛出它。

我建议您选择一个,记录并继续。通常不值得浪费大量时间选择特定的例外情况。记录行为更为重要。

答案 1 :(得分:3)

我会考虑使用ArgumentException来代替这样的事情:

if (string.IsNullOrEmpty(key))
{
    throw new ArgumentException("Expected a key");
}

对于您的示例,我认为InvalidOperationExceptionKeyNotFoundException适合,或者如果您认为合适,只需编写自己的。

纯粹主义者可能不喜欢我的观点,但我的例外情况会在我工作的系统中自动通过电子邮件发送给我,所以最终在大多数情况下我并不关心我抓到的异常 type 只要我能从中获得足够的有用信息,看看发生了什么。这包括:

  1. 易于理解的错误消息
  2. 堆栈跟踪
  3. 必要时的内部异常
  4. 任何额外的背景信息都是可选的奖励。我的意思是,如果你可以在抛出异常的时候捕获任何值,它可以使调试更容易。