我遇到了一个奇怪的问题,想知道应该怎么办。
我有一个返回IEnumerable<MyClass>
的类,它是延迟执行的。目前有两个可能的使用者,其中一个会对结果进行排序。
看下面的例子:
public class SomeClass
{
public IEnumerable<MyClass> GetMyStuff(Param givenParam)
{
double culmulativeSum = 0;
return myStuff.Where(...)
.OrderBy(...)
.TakeWhile( o =>
{
bool returnValue = culmulativeSum < givenParam.Maximum;
culmulativeSum += o.SomeNumericValue;
return returnValue;
};
}
}
消费者仅调用延迟执行一次,但如果他们调用超过一次,则结果将是错误的,因为culmulativeSum
不会重置。 我通过单元测试无意中发现了这个问题。
最简单的解决方法是只需添加 .ToArray()
并消除延迟执行,代价是略微增加一些开销。
我也可以在消费者类中添加单元测试,以确保他们只调用一次,但这不能防止未来编写的任何新消费者出现此潜在问题。
我想到的另一件事是使后续执行抛出异常。
类似这样return myStuff.Where(...)
.OrderBy(...)
.TakeWhile(...)
.ThrowIfExecutedMoreThan(1);
显然这个并不存在。实现这样的事情是个好主意吗?如何做到呢?
否则,如果有一只我看不见的粉色大象,请指出来会很感激。(我感觉有只因为这个问题是关于一个非常基本的场景 :| )
编辑:
以下是一个糟糕的用户使用示例:
public class ConsumerClass
{
public void WhatEverMethod()
{
SomeClass some = new SomeClass();
var stuffs = some.GetMyStuff(param);
var nb = stuffs.Count(); //first deferred execution
var firstOne = stuff.First(); //second deferred execution with the culmulativeSum not reset
}
}
GetMyStuff
时,cumulativeSum
都被设置为0
,但不是每次枚举结果时都会这样。因为每次枚举时,你只评估return
之后的LINQ部分。因此,每次以后你枚举时都将得到空值,因为cumulativeSum
已经大于最大值了。演示:http://ideone.com/VgLbTe。 - mellamokb