允许IList参数为null还是让它抛出异常是否有意义?

时间:2019-07-17 07:17:50

标签: c# collections notnull

这是我昨天遇到的东西。我想知道什么是最佳实践。我可以像这样创建此类的实例,或者来自其他地方的参数可以为null:

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。

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

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);
 }

但是总是检查是否不为null似乎有点尴尬。

2 个答案:

答案 0 :(得分:2)

要添加TheGeneral和Will编写的内容-您永远都不想在生产代码中看到NullReferenceException

您需要做的是确定是否应将空IList传递给此方法,更重要的是,如果可以处理这种情况,则是一种不会破坏业务逻辑的方法。 br /> 如果这两个问题的答案均​​为“否”,则应抛出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,那么您应该在方法内部处理该情况,而不要抛出异常-异常是在特殊情况下发生的-因此,如果空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.
}

答案 1 :(得分:1)

您应该从以下角度考虑:这是否是一个完全的破坏交易者?如果可以的话,在这一点上抛出异常是有道理的,因为这会阻止进一步的操作,但是一个好的实践是,尽可能地远离异常,除非如上所述,它是一个显示停止器。

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

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