Any
将
列举
IEnumerable<T>
.
在这种情况下,
GetNums
事情就是这样
返回a
IEnumerable<int>
对象,其
GetEnumerator()
方法返回一个新的枚举器,该枚举器被重置回初始状态。
以下是一些反编译代码的摘录
https://sharplab.io/
生成,这非常清楚发生了什么。
// GetNums returns an instance of type <GetNums>d__0, with a state of -2
internal static IEnumerable<int> GetEnums()
{
return new <GetNums>d__0(-2);
}
// After Any() consumes the first element of the enumerator, the state is no longer -2
// so GetEnumerator in <GetNums>d__0 returns 'new <GetNums>d__0(0)', which has a state of 0.
// this is as if GetEnums has not been executed at all
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
return this;
}
return new <GetNums>d__0(0);
}
阅读
the spec
,我看不出这个行为是在哪里指定的,所以另一个实现很可能会选择
不
有这种行为。
如果
GetNum
这不是一个纯粹的函数,而且
yield return SomeSideEffect()
相反,
SomeSideEffect()
将被调用两次,第二次可能会产生不同的值。
为了证明这一点
Any()
打电话
MoveNext
在枚举器上,您可以编写自己的类型来实现
IEnumerable<T>
和
IEnumerator<T>
,在
GetEnumerator
方法,返回
this
(与编译器为迭代器块生成的不同)。
class OneToFive: IEnumerable<int>, IEnumerator<int> {
public IEnumerator<int> GetEnumerator() => this;
IEnumerator IEnumerable.GetEnumerator() => this;
public int Current { get; set; }
object IEnumerator.Current => Current;
public bool MoveNext() {
if (Current > 4) return false;
Current++;
return true;
}
public void Reset() { Current = 0; }
public void Dispose() {}
}
var nums = new OneToFive();
Console.WriteLine(nums.Any()); // True
Console.WriteLine(string.Join(", ", nums)); // 2, 3, 4, 5