Enumerable.Empty to List

时间:2015-10-27 09:20:50

标签: c#

例如,如果我有这种方法:

IEnumerable<int> GetRandomNumbers()
{
    // {Codes that generate numbers as List<int>}
    if(generationFails == true)
    {
        return Enumberable.Empty<int>(); // I do this to signal that we have an error
    }
    return numbers;
}

在调用方法中我做:

IEnumerable<int> AddNumber(int number)
{
    var random = GetRandomNumbers();
    var randomList = random  as IList<int> ?? random.ToList(); // Run ToList only if needed
    randomList.Add(number); 
    return randomList;
}

当生成失败时,我得到一个异常“[NotSupportedException:Collection是固定大小的。]”。

这是因为Enumerable empty是一个IList,因此.ToList()没有运行,然后我尝试添加到一个固定的Enumberable.Empty。我错误地认为这是一个糟糕的设计,一个继承IList的对象(其中定义了Add)应该支持Add?

我被迫var randomList = random.ToList()或停止使用Enumberable.Empty吗?还有更好的方法吗?

更新 我想在我的例子中我不清楚。我希望吞下(或记录)错误,但允许操作继续而不会崩溃。我的评论“我这样做是为了表明我们有错误”是为了告诉其他开发人员阅读代码,这是一种异常行为。

蒂姆所关联的问题的answer就是我所得到的。似乎我们没有用于常量集合的接口,因此使用了IList

4 个答案:

答案 0 :(得分:5)

更好的方法是返回null或抛出异常。返回空列表可以被认为是有效的替代,但不是在您的方法的上下文中(例如,过滤另一个没有有效项目的列表)。

失败的随机数生成似乎表明生成算法存在问题,应该抛出异常,而不是空列表。

Should a retrieval method return 'null' or throw an exception when it can't produce the return value?

  

如果您总是希望找到一个值,那么抛出异常(如果缺少)。例外意味着存在问题。

     

如果值可能丢失或存在且两者都对应用程序逻辑有效,则返回null。

答案 1 :(得分:2)

实际上Enumerable.Empty returns an empty array,这就是Array.IList.Add中获得NotSupportedException的原因。数组具有固定的大小。

Why array implements IList?

如果您想要发出错误信息,我会返回null而不是空序列。在可读性方面,对业务逻辑的类型检查并不好。

if(generationFails == true)
{
    return null; // I do this to signal that we have an error
}

然后很容易:

IEnumerable<int> random = GetRandomNumbers();
IList<int> randomList = random == null ? new List<int>() : random.ToList();

空序列表明一切都很好。考虑您将来更改方法以获取整数size。现在有人提供0作为大小,它也返回一个空序列。您不能再区分错误和空序列。

当然,您也可以返回new List<int>而不是Enumerable.Empty<int>

答案 2 :(得分:2)

解决此问题的另一种方法是使用yield break返回空的枚举器:

IEnumerable<int> GetRandomNumbers()
{
    if (generationFails)
        yield break;

    foreach (var element in numbers)
    {
        yield return element;
    }
}

这将使您的IEnumerable<int>懒惰地返回每个随机数。

请注意,这不会将错误单独添加到调用代码中。如果generationFails应该在代码执行中单个错误,那么你应该抛出异常,正如其他人所说的那样。

答案 3 :(得分:0)

使用Enumerable.Empty()方法,您可以使用缓存数组而不是创建一个新数组。这可能会对性能产生积极影响,因为您的代码将很少打扰垃圾收集器。

看看Enumerable.Empty() vs new ‘IEnumerable’() – what’s better?