F#从C#中区分联盟使用

Tom*_*cak 16 c# f# c#-to-f#

使用C#中的F#Discriminated Unions的最佳方法是什么?

我一直在深入研究这个问题,我可能找到了最简单的方法,但由于它相当复杂,可能还有其他一些我看不到的东西......

有一个有区别的联盟,例如:

type Shape =
    | Rectangle of float * float
    | Circle of float
Run Code Online (Sandbox Code Playgroud)

我发现C#的用法是(避免使用变量,使类型明显):

Shape circle = Shape.NewCircle(5.0);
if (circle.IsCircle)
{
    Shape.Circle c = (Shape.Circle)circle;
    double radius = c.Item;
}
Run Code Online (Sandbox Code Playgroud)

在C#中,NewXXXX静态方法总是创建Shape类的对象,还有一种方法IsXXXX来检查对象是否属于该类型; 当且仅当它是,它可以转换为Shape.XXXX类,并且只有它的项目可访问; Shape.XXXX类的构造函数是内部的,即无法访问.

有人知道从一个受歧视的联盟获取数据的更简单的选择吗?

Tom*_*cek 13

如果您正在使用F#编写一个向C#开发人员公开的库,那么C#开发人员应该能够在不了解F#的情况下使用它(并且不知道它是用F#编写的).这也是F#设计指南的推荐.

对于受歧视的工会,这很棘手,因为它们遵循与C#不同的设计原则.因此,我可能会隐藏F#代码中的所有处理功能(如计算区域)并将其作为普通成员公开.

如果你真的需要将这两个案例暴露给C#开发人员,那么我觉得这样的东西对于一个简单的歧视联盟来说是一个不错的选择:

type Shape =
    | Rectangle of float * float
    | Circle of float
    member x.TryRectangle(width:float byref, height:float byref) =
      match x with
      | Rectangle(w, h) -> width <- w; height <- h; true
      | _ -> false
    member x.TryCircle(radius:float byref) =
      match x with
      | Circle(r) -> radius <- r; true
      | _ -> false
Run Code Online (Sandbox Code Playgroud)

在C#中,您可以像熟悉的TryParse方法一样使用它:

int w, h, r;
if (shape.TryRectangle(out w, out h)) { 
  // Code for rectangle
} else if (shape.TryCircle(out r)) {
  // Code for circle
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么你总是建议非详尽的匹配,当它很容易做到详尽? (3认同)
  • 主要是因为上面的方法易于使用并且遵循 C# 中人们已经知道的标准编码风格(例如,使用 `TryParse` 函数是很常见的,并且它不需要您将所有代码都放在 lambda 中 - 大多数 C# 使用lambda 函数是相当小范围的 IMO)。 (2认同)
  • 您是否至少请在这些答案中提及“总数”一词,以便人们可以寻找一些东西来适当地评估这一点?除了主观/模糊(例如,熟悉/惯用)外,请至少考虑包括客观术语(例如,整体)。因为我不了解这些事情,所以我在职业生涯中浪费了无数的时间。我不希望其他人遭受同样的痛苦。 (2认同)

Joh*_*mer 5

根据F#规范,唯一可用的互操作是通过以下实例方法

  • .IsC...

  • .Tag (给每个案例一个整数标签)

  • .Item (在子类型上获取数据 - 仅当存在多个联合案例时才会出现此情况)

但是,您可以自由地在F#中编写方法以使interop更容易.