【问题标题】:How to expose the type as friendly as possible to both C# and F#?如何向 C# 和 F# 公开尽可能友好的类型?
【发布时间】:2013-01-22 16:44:04
【问题描述】:

例如,如果我在 F# 中编写了一个模块

module Lib

type A =
    member this.x1 x = ...

let helpa x = ...
let helpb x = ...

type B =
    member this.y1 x = ...

let helpc x = ...

typeA with
    member this.x2 x = ...
typeB with
    member this.y2 x = ...

open Lib 在 F# 中运行良好,但是,如果我想在 C# 中使用它(我只对 Lib 中的类型和成员函数感兴趣),每次创建类型时我都必须 @ 987654327@。没有办法省略模块名称变得相当烦人。调用像Lib.A.C() 这样的静态方法就更麻烦了。

然后我尝试将module 替换为namespace,每次引入一些​​辅助函数时,我都必须创建一个具有新名称的新模块。有时我可以设法将所有辅助函数重新排列到 1 个模块中,但这会导致代码的可读性降低。

什么是更好的结构?

希望我有:Using * = Lib.* 用于 C#。

【问题讨论】:

标签: f#


【解决方案1】:

F# 在这里提供了比 C# 更大的灵活性,因此我将以标准方式将它公开给 C#,即将类型包含在命名空间中。我认为,这样的东西提供了两全其美:

namespace Lib

type A =
    member this.x1 x = ()

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module A =
  let helpa x = ()
  let helpb x = ()

type B =
    member this.y1 x = ()

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module B =
  let helpb x = ()

type A with
    member this.x2 x = ()
type B with
    member this.y2 x = ()

F# 系列遵循类似的设计。您可以使用 [&lt;AutoOpen&gt;] 和 [&lt;RequireQualifiedAccess&gt;] 属性进一步控制如何从 F# 使用模块。

【讨论】:

  • daniel,关于如何以对 c# 友好的方式公开 f# 类型(如联合、记录类型)的任何指导?
  • @l--''''''------''''''''''''' 最近一直在做一些互操作,发现f#如果您使用新的基于表达式的 switch 语法,就像在 f# 中使用 match 一样,联合实际上会很好地暴露出来。无论如何,记录只是只读类,所以非常自然。
  • 我上面提到的一个例子: switch (result) { case var checkResult when checkResult.IsOk: HandleOk(checkResult.OkValue);休息; case var checkResult when checkResult.IsError: HandleError(checkResult.ErrorValue);休息; }
  • 我刚刚在这里找到了一篇很棒的文章:connelhooley.uk/blog/2017/04/30/…
  • 除了我原来对结果类型的建议之外,如果联合案例有内容,你可以做 switch (unionInstance) { case Union.FirstType content: HandleFirstType(content.Item);休息; case Union.SecondType 内容:HandleSecondType(content.Item);休息; }
【解决方案2】:

我认为您已经在答案中提到了最佳选择 - 在顶部定义带有 namespace 声明的文件(这样,您可以在 C# 中只编写 using Lib),然后将所有辅助函数放在模块中。

与某种类型(例如 A)明确关联的辅助函数可以放入名为 A 的模块中(类似于 List 模块中与 List&lt;'T&gt; 类型关联的 F# 函数) .

这需要做更多的工作,因为您需要使用特殊属性标记模块(以避免名称冲突),但它在 F# 和 C# 中都很容易使用(而且我认为更好地使用更重要而不是在构建库时节省一些击键):

namespace Lib

// Declaration of the 'A' type and helper functions in 'A' module 
type A() =
  member this.x1 x = 10

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module A = 
  let helpa (x:A) = x.x1
  let helpb (x:A) = x.x1

// Declaration of the 'B' type and helper functions in 'B' module 
type B() =
  member this.y1 x = 10

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module B = 
  let helpc (x:B) = x.y1

// Member augmentations for easy use from C#
type A with
    member this.x2 x = A.helpa this
type B with
    member this.y2 x = B.helpc this

【讨论】:

  • 在 C# 中,A.helpa 变为 AModule.helpa。我必须将函数添加为 A 类型的静态成员。
猜你喜欢
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
相关资源
最近更新 更多