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

发布于 2024-09-03 21:00:27 字数 1262 浏览 4 评论 0原文

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

let map_add valueToAdd xs =
    xs |> Seq.map (fun x -> x + valueToAdd)

生成的 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); }
}

并查看几乎相同的 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);
    }
}

以及为 C# lambda 表达式生成的代码:

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

所以我有一些问题:

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

Let's look at the code, generated by F# for simple function:

let map_add valueToAdd xs =
    xs |> Seq.map (fun x -> x + valueToAdd)

The generated code for lambda expression (instance of F# functional value) will looks like this:

[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); }
}

And look at nearly the same C# code:

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);
    }
}

And the generated code for the C# lambda expression:

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

So I have some questions:

  • Why is F#-generated class not marked as sealed?
  • Why does F#-generated class contain public fields since F# doesn't allow mutable closures?
  • Why does F# generated class have a constructor? It may be perfectly initialized with the public fields...
  • Why is C#-generated class not marked as [Serializable]? Also classes generated for F# sequence expressions also became [Serializable] and classes for C# iterators do not.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

五里雾 2024-09-10 21:00:27

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

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

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

Since they are compiler-generated, the sealed / public field issues are a bit moot - you shouldn't ever see it except via debug tools - how would you be subclassing it or mutating it, except by stepping around the compiler? If you have that level of debug access you can mutate it anyway (via reflection).

For C# it needs top be a field to allow certain ref / out usage, and to allow correct usage with captured mutable structs (yes, evil, we know). I assume F# is similar here (can you mutate a sub-[sub-[sub-]]member of the captured value?). The members could probably be internal, though.

Re [Serialziable]; why would something that underpins a closure be serializable? Delegates make extremely poor serialization candidates. Maybe the nature of F# means that it is better suited to persisting an operation (mid-flow) to disk - but in general, I wouldn't recommend it. I would have no expectation of these objects (iterators and capture-classes) being serialzable.

黎夕旧梦 2024-09-10 21:00:27

为什么 F# 生成的类没有标记为密封?

因为编译器不这样做(这最终是代码生成的选择。

既然 F# 不允许可变闭包,为什么 F# 生成的类包含公共字段?

您需要能够获取对实例的引用才能对其进行修改。但你不能,所以可修改并不重要。这可能避免了在闭包中捕获可变值的特殊情况。

为什么 F# 生成的类有构造函数?它可以用公共字段完美地初始化......

再次是代码生成选择。

为什么 C# 生成的类没有标记为 [Serializable]?此外,为 F# 序列表达式生成的类也变成了 [Serialized],而为 C# 迭代器生成的类却没有。

更多代码生成选择。

这些选择都是开发人员可见的(即对客户端代码没有影响),它确实没有区别。

Why is F#-generated class not marked as sealed?

Because the compiler doesn't (this is in the end a code generation choice.

Why does F#-generated class contain public fields since F# doesn't allow mutable closures?

You would need to be able to get to a reference to an instance to modify it. But you can't, so being modifiable doesn't matter. And likely this avoids needing to special case where a mutable is captured in a closure.

Why does F# generated class have a constructor? It may be perfectly initialized with the public fields...

Again code generation choice.

Why is C#-generated class not marked as [Serializable]? Also classes generated for F# sequence expressions also became [Serializable] and classes for C# iterators do not.

More code generation choices.

None of these choices is developer visible (i.e. make no difference to client code) it really makes no difference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文