好的做法 - 抛出异常以满足函数返回

时间:2013-11-13 14:50:17

标签: c# error-handling return

构建一个自定义IDataReader,它在XML中查找与特定元素名称匹配的值,如果找到,则返回值。 GetValue函数 - 必须返回由接口指定的Object,如下所示:

    public object GetValue(int i)
    {
        string SearchString = _columns[i];

        var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
        if (searchedAttributeValue.Count() > 0)
        {
            return ParseTypes(searchedAttributeValue.First().Value);
        }

        var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
        if (searchedElementValue.Count() > 0)
        {
            return ParseTypes(searchedElementValue.First().Value);
        }
    }

显然,这不会构建,因为它可能在没有有效返回的情况下到达函数的末尾。

在这种情况下,如果发生这种情况,则意味着存在配置错误 - 用户正在寻找XML中不存在的元素或属性。

我发现(这对我来说是新的)你可以通过这样做解决问题:

    public object GetValue(int i)
    {
        if (_el == null)
        {
            _el = XNode.ReadFrom(_reader) as XElement;
        }
        string SearchString = _columns[i];

        var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
        if (searchedAttributeValue.Count() > 0)
        {
            return ParseTypes(searchedAttributeValue.First().Value);
        }

        var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
        if (searchedElementValue.Count() > 0)
        {
            return ParseTypes(searchedElementValue.First().Value);
        }

        throw new Exception("oh crap!");
    }

因此该函数不会返回,只会抛出错误。

但是,这种方法存在根本性的错误。它没关系,为什么它没关系/不好,是否有更好的方法来处理这种情况?

5 个答案:

答案 0 :(得分:6)

除非你真的需要 catch块,否则你不需要引入try / catch / finally。您可以在初始方法的末尾添加throw语句。

一路上,我开始使用FirstOrDefault(),遵循局部变量的正常C#命名约定,当它们不是非常有用时停止使用查询表达式,并抛出一个更具体的异常:

public object GetValue(int i)
{
    string searchString = _columns[i];

    var searchedAttribute = _el.Attributes(searchString).FirstOrDefault();
    if (searchedAttribute != null)
    {
        return ParseTypes(searchedAttribute.Value);
    }

    var searchedElement = _el.Elements(searchString).FirstOrDefault();
    if (searchedElement != null)
    {
        return ParseTypes(searchedElement.Value);
    }
    // Nothing found - oops.
    throw new SomeSpecificException("Some message here");
}

如果您需要catch块进行日志记录,我可能会尝试捕获特定的异常,这可能意味着无论如何都要将其移入ParseTypes(因为您不应该&#39} ; t从其余调用中获取任何异常...)无论哪种方式,最后都要保留throw语句。

编辑:在设计方面,是否应该在未找到值时抛出异常,实际上取决于期望值。我们无法知道这是否表明系统出现了问题,或者只是完全正常的数据缺失。这应该决定你的选择。特别是,如果每个调用者都试图捕获异常,那么这就是设计气味,您应该返回null或使用类似Dictionary<,>.TryGetValue方法的东西。

答案 1 :(得分:2)

我喜欢使我的方法类似于.NET框架Parse()和TryParse()方法。在你的情况下,我会做:

public object GetValue(int i)
{
    // ...

    // fail
    throw new Exception("Cannot get value");
}

或做:

public bool TryGetValue(int i, out object result)
{
    // ...

    // fail
    result = null;
    return false;
}

答案 2 :(得分:1)

尝试捕获是无关紧要的。你可以简单地将你的代码重构为:

public object GetValue(int i)
{

   if (_el == null)
   {
      _el = XNode.ReadFrom(_reader) as XElement;
   }
     string SearchString = _columns[i];

   var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
   if (searchedAttributeValue.Count() > 0)
   {
      return ParseTypes(searchedAttributeValue.First().Value);
   }

   var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
   if (searchedElementValue.Count() > 0)
   {
      return ParseTypes(searchedElementValue.First().Value);
   }

   throw new Exception("oh crap!");
}

这具有相同的净结果。


那说抛出异常是昂贵的(计算)。如果你想要炸弹(完全停止处理,这是一个主要问题,它应该只是死)然后抛出一个异常。

如果只是一种确定何时未满足if语句的方法,可以将其更改为TryParse类型函数:

public bool GetValue(int i, out object returnVal)
{

   if (_el == null)
   {
      _el = XNode.ReadFrom(_reader) as XElement;
   }
     string SearchString = _columns[i];

   var searchedAttributeValue = from nm in _el.Attributes(SearchString) select nm;
   if (searchedAttributeValue.Count() > 0)
   {
      returnVal = ParseTypes(searchedAttributeValue.First().Value);
      return true;
   }

   var searchedElementValue = from nm in _el.Elements(SearchString) select nm;
   if (searchedElementValue.Count() > 0)
   {
      returnVal = ParseTypes(searchedElementValue.First().Value);
      return true;
   }

   return false;
}

然后

if (GetValue(i, out value))
   //success
else
   //it's failed.

答案 3 :(得分:1)

如果由于配置错误而导致搜索不会返回任何内容的真正特殊情况,那么无论如何都要抛出异常。这个问题是延续的。如果找不到项目,客户端代码是否可以继续?如果可以的话,客户端代码将需要仔细检查从您的代码抛出的任何异常,以确定它是否因为某个项目不存在而被抛出,或者因为其他错误而无法继续执行。

另一个选项是返回指示未找到值的内容,并允许调用代码来处理它。您可以返回null以指示调用代码没有找到任何项目,并且在此实例中可能没问题。一个更好的解决方案可能是创建一个简单的Optional<T>类,它包含对象是否存在(可能是HasValue)的指示,以及对象本身(如果有)。调用代码可以轻松,更具体地检查对象是否被返回并处理不存在的情况,并且异常不需要额外的审查。

编辑:一个更好的替代方案可能是其他人提出的ParseTryParse范例,但我认为这个答案可能有一些用处,所以我会留在这里:)

答案 4 :(得分:0)

这种方法有很多不好的做法:应始终避免使用catch (Exception)。只捕捉你期望的例外。另外,throw Exception()是不好的风格。总是扔一些更具体的东西。但是对于你正在寻找的东西:毕竟你根本不需要一个,只需要放置一个throw new ArgumentException()或者其他东西作为函数的最后一行。这是一个很好的做法,如果代码曾在那里运行,那真的是一个编程错误。