f#区别于c#的联合使用

本文关键字:区别于 | 更新日期: 2023-09-27 18:04:48

在c#中使用f#鉴别联合的最佳方法是什么?

我研究这个问题已经有一段时间了,我可能已经找到了最简单的方法,但由于它相当复杂,可能还有一些其他的东西我没有看到…

具有区别对待的联合,例如:

type Shape =
    | Rectangle of float * float
    | Circle of float
我发现c#中

的用法是(避免使用变量,以使类型明显):

Shape circle = Shape.NewCircle(5.0);
if (circle.IsCircle)
{
    Shape.Circle c = (Shape.Circle)circle;
    double radius = c.Item;
}

在c#中,NewXXXX静态方法总是创建Shape类的对象,还有一个IsXXXX方法来检查对象是否属于该类型;当且仅当是,它是可浇注到Shape.XXXX类的,并且只有当它的项目是可访问的;Shape.XXXX类的构造函数是内部的,即不可访问。

有没有人知道从一个受歧视的联合中获取数据的更简单的选项?

f#区别于c#的联合使用

如果你正在用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
在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
}

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

  • .IsC...

  • .Tag(给每个大小写一个整数标记)

  • .Item(在获取数据的子类型上-这仅在有多个联合情况时出现)

但是,您可以自由地在f#中编写方法以使互操作更容易。

假设我们需要计算每个Shape的面积多态

在c#中,我们通常会创建一个假设的对象层次结构和一个访问者。在这个例子中,我们必须创建一个ShapeVisitor类,然后创建一个派生的ShapeAreaCalculator visitor类。在f#中,我们可以对Shape类型使用模式匹配:
let rectangle = Rectangle(1.3, 10.0)
let circle = Circle (1.0)
let calculateArea shape =
    match shape with
    | Circle radius -> 3.141592654 * radius * radius
    | Rectangle (height, width) -> height * width
let rectangleArea = calculateArea(rectangle)
// -> 1.3 * 10.0
let circleArea = calculateArea(circle)
// -> 3.141592654 * 1.0 * 1.0