24

假设一个简单的示例,其中方法检索一个集合(例如包含一些配置字符串的列表)并尝试以某种方式检查它:

void Init()
{
    XmlDocument config = new XmlDocument();
    config.Load(someXml);
    var list = config.SelectNodes("/root/strings/key"); // Normally, list should not be null or empty

    if (list == null || list.Count == 0)
        throw new SomeExceptionType(message);   // What kind of exception to throw?

    // Iterate list and process/examine its elements
    foreach (var e in list) ...
}

在此特定实例中,如果没有检索到任何内容,该方法将无法正常继续。我不确定在这种情况下要抛出什么异常类型。据我所知,我的选择是:

  • 手动抛出任何东西并让其NullReferenceException自动抛出(不处理空列表情况),

  • 抛出自定义异常类型(可能不是一个好主意,因为我预计调用者不会尝试对异常做任何事情,即他不会寻找要处理的特定异常类型),

  • 做别的事?
4

4 回答 4

14

Enumerable.FirstSystem.InvalidOperationException如果集合为空,则抛出。你也可以,我猜。

throw new InvalidOperationException("Sequence contains no elements");

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.first?view=netframework-4.8

于 2019-07-23T14:31:25.760 回答
13

您可以为适当的逻辑创建自己的异常类型:

public class InitializationException : Exception
{
}

接着:

throw new InitializationException {Message = "Collection is empty"};
于 2013-09-05T13:45:21.303 回答
2

我不确定在这种情况下你可以优雅地抛出一个内置异常......aNullReferenceException是不合适的,因为空列表不是空引用

我建议使用 Dmintry 提出的解决方案,因为调用者仍然可以使用try...catch(Exception),而不必知道或关心异常确实是SuperDooperListNullOrEmptyFunTimeException

因为从调用者的角度来看,这要么是一个不可恢复的错误(即他们无法控制所选的 Xml 路径,也无法控制正在加载的 XML),因此异常只会被转储到日志中或在屏幕上供人类消费,此时它没有实际意义-因为实际消息比类型更重要。

另一方面,如果它是可恢复的(调用者可以在确保要加载的 xml 现在包含正确格式的 xml 后重试该方法,或者调用者可以通知用户并要求他们去修复 XML 和“你想现在重试吗?”之类的东西)那么你需要给他们一个类型化的异常,这样他们就知道重试是安全的,而不是一个普通的旧异常,这可能意味着其他事情发生了可怕的错误,重试只会让事情变得更糟...

于 2013-09-05T15:01:43.013 回答
0

这不是太多的编程问题,因为它是一个设计问题,.NET 列表对象在它们为空时不会引发异常的原因是因为在很多情况下,空列表是可预期和可接受的情况。

如果在上下文中您使用的列表永远不应该为空,则抛出异常(自定义异常)

但是,如果列表可能为空是可能且合乎逻辑的,那么为什么要中断整个事情,它是例外而不是例外,所以需要例外?循环和空列表foreach不会引发异常,循环根本不会循环。

至于 null 的可能性(SelectNodes如果理解得很好,则很少见)这是同样的问题,在某些返回 a 的库或函数null中是正常行为而不是异常。

于 2013-09-05T13:55:42.067 回答