seq 是 IEnumerable 接口的别名,然后您可以创建实现 IEnumerable 的对象并使用它的方法,例如:
IEnumerable<int> list = new List<int> { 1, 2, 3, 4, 5 };
并使用IEnumerable方法:
Where, Max, etc.
但是你必须实例化一个实现 IEnumerable 的对象。
但是......在F#中你可以创建一个类似的序列:
let list = seq { for i in 1..5 -> i }
Visual Studio说你的列表有 seq 类型。这是不可能的, seq 是一个接口( IEnumerable ),您无法创建接口的实例。
那么, seq 里面的魔力是什么?
在FSI中使用GetType:
let goingToSee = seq { for i in 1..5 -> i }
goingToSee.GetType();;
val goingToSee : seq<int>
val it : System.Type = FSI_0010+goingToSee@12
答案 0 :(得分:2)
F#中的seq { .. }
表达式更类似于C#中的迭代器方法(使用yield
关键字编写)而非集合初始值设定项。与C#编译器处理迭代器类似,F#编译器将seq { .. }
表达式转换为实现IEnumerable<T>
的类。
编译后的类继承自GeneratedSequenceBase
(参见source code),并根据您在序列表达式中编写的内容生成代码。它被编译为状态机,因此代码看起来有点难看,但是如果你使用ILSpy来看它,它看起来像这样:
internal sealed class list@6 : GeneratedSequenceBase<int> {
public override int GenerateNext(ref IEnumerable<int> next) {
switch (this.pc) {
case 1: goto IL_82;
case 2: this.i = 0; break;
case 3: goto IL_A3;
default: {
this.@enum = Operators.OperatorIntrinsics.RangeInt32(1, 1, 5).GetEnumerator();
this.pc = 1;
break; }
}
if (this.@enum.MoveNext()) {
this.i = this.@enum.Current;
this.pc = 2;
this.current = this.i;
return 1;
}
IL_82:
this.pc = 3;
LanguagePrimitives.IntrinsicFunctions.Dispose<IEnumerator<int>>(this.@enum);
this.@enum = null;
this.pc = 3;
IL_A3:
this.current = 0;
return 0;
}
}
我不会尝试对此进行解码,但我认为pc
会保留状态机的状态。根据它,它可以初始化迭代器,移动到下一个状态,或者处置可能使用的任何资源。
值得注意的是,名称list@6
中的6是此生成类所来自的行号。