在多个点抛出异常(重构)

时间:2015-10-20 14:36:18

标签: c# coding-style

我正在编写一个接受用户输入的函数,在我们的数据库中运行一个过程,并比较这些值。在此过程中,我需要检查我们是否已收到正确的输入,然后该查询已返回可接受的值。

    private void DoTheThing(int? userInput1, int? userInput2, int valuePassedIn)
    {
        if (userInput1 == null || userInput2 == null)
        {
            Exception ex = new Exception();
            ex.Data.Add("Message", "You screwed up.");
            throw ex;
        }

        var queryResult = 0; //execute a query using the non-null inputs

        if (queryResult == null) //or otherwise doesn't return an acceptable value
        {
            Exception ex = new Exception();
            ex.Data.Add("Message", "some other thing happened");
            throw ex;
        }
        else
        {
            //We're good, so do the thing
        }
    }

关于此问题的快速说明:我了解argument against exceptions as flow control并且在我得到这个目标之前,最好先查看用户的输入。我不会详细了解所有细节,但是请接受我有点像这样写功能。

有人说过,这是我的问题:

鉴于这两个例外之间的唯一区别是消息和它们被抛出的时间,我如何清除此代码为 DRY 并避免在确定后运行不必要的代码出现问题吗?

我考虑使用goto并将错误代码放在那里,但这实际上只会解决问题。如果我将异常代码移到底部并检查message变量(或类似的变量),那么我只是运行不需要首先运行的代码。< / p>

4 个答案:

答案 0 :(得分:1)

您最好创建一个BadInputException类和一个NullQueryResultException类。这些做了两件事,抛出一个特定的异常比抛出一个通用的异常(...)更好。事实上,我认为FXCop或Visual Studio的代码分析会给你一个关于抛出泛型异常的警告。

要编写的代码并不是那么多。

public class BadInputException : Exception 
{
    public BadInputException()
    {
        this.Data.Add("Message", "You screwed up.")
    }
}

然后代替:

Exception ex = new Exception();
ex.Data.Add("Message", "You screwed up.");
throw ex;

这样做:

throw new BadInputException();

编辑:将“You screwed up”消息从Message属性移动到Data集合以匹配OP想要的内容。

答案 1 :(得分:1)

我建议不要抛出Exception(这意味着出错了,没有评论可用),但ArgumentNullExceptionInvalidOperationException类。另一项修正案是 arrow-head 反模式:

private void DoTheThing(int? userInput1, int? userInput2, int valuePassedIn)
{
    // What actually went wrong? An argument "userInput1" is null
    if (null == userInput1)
      throw new ArgumentNullException("userInput1"); 
    else if (null == userInput2)
      throw new ArgumentNullException("userInput2"); // ...or userInput2 is null

    var queryResult = executeSomeQuery(userInput1, userInput2, valuePassedIn);

    // What went wrong? We don't expect that null can be returned;
    // so the operation "executeSomeQuery" failed:
    // we've provided validated (not null) values and got unexpected return.
    // Let it have been known. 
    if (null == queryResult) 
      throw new InvalidOperationException(
        String.Format("Query ({0}, {1}, {2}) returned null when bla-bla-bla expected", 
          userInput1, userInput2, valuePassedIn));   

    // We're good, so do the thing
    // Note that's there's no "arrow-head antipattern": 
    // we're not within any "if" or "else" scope 
}

修改:由于每个*Exception都是从Exception继承的,因此您可以将一些信息放入Data

  Exception ex = new ArgumentNullException("userInput1");
  ex.Data.Add("Some key", "Some value");
  throw ex;

但通常Message是一个更好的解释已经发生的事情的地方。

答案 2 :(得分:0)

我会创建一个方法:

private void CheckResult(bool cond, string msg, string info) {
    if (!cond)
        return;

    Exception ex = new Exception();
    ex.Data.Add(msg, info);
    throw ex;
}

并致电

CheckResult(userInput1 == null || userInput2 == null, "Message", "You screwed up.");

CheckResult(queryResult == null, "Message", "You screwed up.");

答案 3 :(得分:0)

我认为问题Refactoring Guard Clauses对您有所帮助。

Replace Nested Conditional with Guard Clauses中有一些相关内容。

希望它有用。