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

How can I tell if an IEnumerable has been evaluated?

我能知道 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
    }
}

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

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

有时 IEnumerator<> 会支持 Reset() 方法,但这不是您所要求的。当您尝试 Reset().

时,许多枚举器只会抛出异常

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

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

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

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

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

您可以为 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
    }
}