【问题标题】:Does it make sense to allow IList parameter to be null or throw exception if null?允许 IList 参数为空或如果为空则抛出异常是否有意义?
【发布时间】:2019-11-25 23:18:22
【问题描述】:

这是我昨天遇到的。我想知道这里的最佳做法是什么。我可以像这样创建此类的一个实例,或者来自其他地方的参数可以为空:

CustomItemsSourceDialogViewModel itemsSource = new CustomItemsSourceDialogViewModel();
itemsSource.Initialize(null); // I get nullReferenceException

这是上面提到的类定义:

public class CustomItemsSourceDialogViewModel
{
  public void Initialize(IList<string> items)
  {
    // it doesn't make sense to allow parameter items to be null
    // it only makes sense to allow not null items collection
    // so we can operate on it.
    // if items is null we get system.nullReferenceException
    if (items.Count > 0)
      // aggregate is a system.linq static method
      this.ItemsSource = items.Aggregate((x, y) => x + "\r\n" + y);
  }
}

我更喜欢让我的集合/列表不为空。换句话说,集合应该有一个空集合的默认值。这样开发者或用户就不会得到那个讨厌的 NullReferenceException。

关于方法的列表参数,当参数为空时我是否应该抛出异常并通知用户:

public void Initialize(IList<string> items)
{
  if( items == null )
    throw new Exception("Parameter items is null. It should be a valid list.");
  ...

另一种解决方案是检查它是否不为空:

public void Initialize(IList<string> items)
{
  if (items != null && items.Count > 0)
    this.ItemsSource = items.Aggregate((x, y) => x + "\r\n" + y);
 }

但是总是检查 if not null 似乎有点尴尬。

【问题讨论】:

  • 这是一个时尚感的问题,取决于你写这篇文章的水平,也涉及到常识。如果它是 null 的特殊情况,那么你抛出一个 ArgumentNullException。用户是否期望它在这里是null?忽略此null 是否有任何重大影响?低级 api 被大量验证,因为它们经过大量测试并且需要一致的结果,高级混合在一起的代码往往有更多的余地。但是还是回到了原点,是不是很特别?
  • 我同意上述观点,这取决于 ItemsSource 具有值的重要性。你可以简单地做: if( items == null ) return;或 if( items == null ) this.ItemsSource = new List()。这将允许您继续执行。

标签: c# collections notnull


【解决方案1】:

为了补充 TheGeneral 和 Will 所写的内容 - 你永远不想在生产代码中看到 NullReferenceException

您需要做的是确定是否希望将 null IList 传递给此方法,更重要的是,如果您可以处理此类情况,是一种不会破坏业务逻辑的方法。
如果这两个问题的答案都是“否”,那么您应该抛出一个ArgumentNullException - 因为这个异常以最精确的方式传达了问题 - 该方法期望参数不为空:

public void Initialize(IList<string> items)
{
    if( items is null ) // requires c# 7 or higher
    { 
        throw new ArgumentNullException(nameof(items));
    }

    // rest of the code here
}

但是,如果您的业务逻辑可以在没有 IList 的情况下继续进行,并且预计将 null 发送到此方法,那么您应该在方法内部处理这种情况,而不是抛出异常 - Exceptions 是针对特殊情况的 - 因此,如果 null IList 与空 IList 具有相同的效果,并且预计会被传递到方法中 - 它不能被视为异常,因此不应该触发抛出异常。

public void Initialize(IList<string> items)
{
    // just a shorter way for the same condition - requires c# 6 or higher
    if (items?.Any() ?? false)
    {
        this.ItemsSource = Items.Aggregate((x, y) => x + "\r\n" + y);
    } // I like to always use code blocks for conditions etc'. I find it more readable.
}

【讨论】:

  • 感谢您提供如此详尽的答案。这取决于我猜的业务逻辑。
  • 很高兴为您提供帮助 :-)
【解决方案2】:

您应该从以下角度思考:这是否完全破坏了交易?如果是,那么此时抛出异常是有意义的,因为它会阻止进一步的操作,但是一个好的做法是尽可能远离异常,除非如上所述它是一个阻碍。

在您的情况下(我理解它是特定列表功能的包装器),为什么您没有像这样内联初始化默认列表值并让用户添加单个项目或参数。或者,如果它不是交易破坏者,您最终可以检查 null。

public List<string> ItemSource { get; set; } = new List<string>();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 2019-01-12
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多