设计一个可以从F#中使用的C#库的指南

我只是想指出,这个问题不是相反的

设计F#库以供F#和C#使用的最佳方法

在这里,我不是要问如何设计一个用于两个世界的C#函数库。

我想知道什么样的设计选择包含或避免得到合理的折衷方案以使这个库可以从F#中使用的 良好实践

像(例如)的做法:

  • 保持对象层次结构尽可能简单

  • 避免改变对象的状态,但返回新的对象

  • 等等…

任何已经完成它的人都可以分享它的经验吗?

边注

有趣的是,这个OSS项目IronJS 。 是的,它是用F#编写的,但是作者公开了两个专门的主机IronJS.Hosting.FSharpIronJS.Hosting.CSharp

想象一下,有一天你想在F#中重写你的C#库以获得更好的可用性。 以下是您可能采取的路径:

在此处输入图像描述

我专注于“命令C# – >functionC# – >functionF# – >惯用F#”这一路径。 C#库function越多,您的库在F#中的可用性就越大 。 function风格有助于提高可组合性,并且更接近于惯用的F#代码。 沿着这些方向,你可以:

  • 默认拥抱不变性原则。 如果您不知道以后是否需要更新字段/属性,请先将其标记为readonly
  • 遵循基于表达式和声明性编程风格。 LINQ操作就是很好的例子。
  • 以不可变的方式使用不可变集合或可变集合。 随着C#immutable集合的引入 ,它应该比以往更容易。

上图是从F#中获取的乐趣和利润 从C#移植到F#系列 。 他们非常有帮助; 了解如何在F#中表达C#概念将提高库的可用性。

很难避免C#的面向对象特性。 请记住,F#类型推断对这些function不起作用。 沿着保持对象层次结构简单的方法,您应该减少成员重载的数量。 大量的成员重载很容易混淆F#类型检查器。 而且, 使用C#库分发一个瘦F#包装器并没有什么坏处。 您需要做的一些事情是将一些方法转换为模块函数并创建活动模式以分解对象层次结构。

与现有.NET库互操作是F#的主要设计目标,因此对要使用的库没有任何限制。

也就是说,由于F#更严格的打字,有些模式导致代码略显笨拙。 构建器模式是一个。

 var bldr = new StringBuilder(); bldr.Append("abc"); //ignoring return value 

 bldr.Append("abc") |> ignore //must be explicitly ignored 

但是这很容易使用扩展方法或let-bound函数。 底线:互操作是F#的优势和最大成就之一。