如何判断IEnumerable是否已被评估?

时间:2015-04-02 15:31:58

标签: c# ienumerable iqueryable

我是否可以知道IEnumerable(或IQueryable)的延迟评估是否已经发生?也就是说,是否曾调用GetEnumerator().MoveNext()。有办法吗?

如何在以下示例中对HasBeenEvaluated()进行编码?

private void Example()
{
    IEnumerable<Thing> things = _Repository.GetObjects<Thing>();

    bool x = HasBeenEvaluated(things); // returns false

    foreach (var thing in things)
    {
         x = HasBeenEvaluated(things); // returns true
    }
}

3 个答案:

答案 0 :(得分:1)

一般来说,没有。接口IEnumerable<>不支持。

另外,如果你有一个IEnumerator<>,你通常无法判断是否曾调用MoveNext()

有时IEnumerator<>会支持Reset()方法,但这不是您要求的。当您尝试Reset()时,许多枚举器只会抛出异常。

答案 1 :(得分:1)

您可以为IEnumerable创建一个包装器,在迭代时,翻转一个布尔值以指示它已被迭代:

//TODO come up with a better name
public class Foo<T> : IEnumerable<T>
{
    private IEnumerable<T> wrapped;
    public Foo(IEnumerable<T> wrapped)
    {
        this.wrapped = wrapped;
    }
    public bool HasBeenIterated { get; private set; }
    public IEnumerator<T> GetEnumerator()
    {
        HasBeenIterated = true;
        foreach (var item in wrapped)
            yield return item;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

您的方法现在可以成为:

private void Example()
{
    var things = new Foo<Thing>(_Repository.GetObjects<Thing>());

    bool x = things.HasBeenIterated;//is false

    foreach (var thing in things)
    {
        x = things.HasBeenIterated;//is true
    }
}

答案 2 :(得分:0)

也许您可以从类型继承并向其添加方法以返回状态。

在这种情况下,您将向此类添加一个属性,该属性将反映正在调用的操作的状态。

public class StatefulThings : IEnumerable<Thing>
{
  bool _moveNextExecuted = false;

  public override bool MoveNext()
   {
      // Perform next pointer

      // Set state of hasBeenEnumerated in here...
      _moveNextExecuted  = true;
   }
}