C#和F#lambda表达式代码生成

con*_*low 25 c# lambda serialization f#

让我们看一下F#为简单函数生成的代码:

let map_add valueToAdd xs =
    xs |> Seq.map (fun x -> x + valueToAdd)
Run Code Online (Sandbox Code Playgroud)

生成的lambda表达式代码(F#功能值的实例)如下所示:

[Serializable]
internal class map_add@3 : FSharpFunc<int, int> {
    public int valueToAdd;
    internal map_add@3(int valueToAdd) { this.valueToAdd = valueToAdd; }
    public override int Invoke(int x)  { return (x + this.valueToAdd); }
}
Run Code Online (Sandbox Code Playgroud)

看看几乎相同的C#代码:

using System.Collections.Generic;
using System.Linq;

static class Program {
    static IEnumerable<int> SelectAdd(IEnumerable<int> source, int valueToAdd) {
        return source.Select(x => x + valueToAdd);
    }
}
Run Code Online (Sandbox Code Playgroud)

并为C#lambda表达式生成代码:

[CompilerGenerated]
private sealed class <>c__DisplayClass1 {
    public int valueToAdd;
    public int <SelectAdd>b__0(int x) { return (x + this.valueToAdd); }
}
Run Code Online (Sandbox Code Playgroud)

所以我有一些问题:

  • 为什么F#生成的类没有标记为sealed
  • 为什么F#生成的类包含公共字段,因为F#不允许可变闭包?
  • 为什么F#生成的类有一个构造函数?它可以用公共领域完美地初始化......
  • 为什么C#生成的类没有标记为[Serializable]?此外,为F#序列表达式生成的类也变为了[Serializable],而C#迭代器的类则没有.

Mar*_*ell 4

由于它们是编译器生成的,所以密封/公共字段问题有点没有实际意义 - 除了通过调试工具之外,您不应该看到它 - 除了绕过编译器之外,您将如何子类化它或改变它?如果您具有级别的调试访问权限,您无论如何都可以改变它(通过反射)。

对于 C#,它需要 top 是一个字段来允许某些ref/out使用,并允许正确使用捕获的可变结构(是的,邪恶,我们知道)。我假设 F# 在这里是类似的(你可以改变捕获值的 sub-[sub-[sub-]] 成员吗?)。不过,这些成员可能是内部成员。

关于[Serialziable]; 为什么支撑闭包的东西是可序列化的?代表们是极差的连载候选人。也许 F# 的本质意味着它更适合将操作(中流)持久保存到磁盘 - 但总的来说,我不推荐它。我不期望这些对象(迭代器和捕获类)是可序列化的。