如果列表/集合为空或 null 且无法迭代(不是参数),则引发的异常类型

本文关键字:参数 类型 异常 迭代 集合 列表 null 如果 | 更新日期: 2023-09-27 18:30:22

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

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被抛出自动(不处理空列表情况),

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

  • 做点别的?

如果列表/集合为空或 null 且无法迭代(不是参数),则引发的异常类型

如果集合为空,Enumerable.First会抛出System.InvalidOperationException。我猜你也可以。

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

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

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

public class InitializationException : Exception
{
}

然后:

throw new InitializationException {Message = "Collection is empty"};

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

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

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

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

这不是

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

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

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

至于空的可能性(如果理解得很好,对于SelectNodes来说非常罕见),这是同样的问题,在某些库或函数中,返回null是一种正常行为而不是例外。