F# Discriminated Union usage from C# [duplicate]

放肆的年华 提交于 2019-11-29 01:26:22

If you are writing a library in F# that is exposed to C# developers, then C# developers should be able to use it without knowing anything about F# (and without knowing that it was written in F#). This is also recommended by F# design guidelines.

For discriminated unions, this is tricky, because they follow different design principles than C#. So, I would probably hide all processing functionality (like calculating area) in the F# code and expose it as ordinary members.

If you really need to expose the two cases to C# developers, then I think something like this is a decent option for a simple discriminated union:

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

In C#, you can use it in the same way as the familiar TryParse methods:

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

According to the F# spec, the only interop available is through the following instance methods

  • .IsC...

  • .Tag (which gives an integer tag to each case)

  • .Item (on the subtypes to get the data - this is only present when there is more than one union case)

However, you are free to write methods in the F# to make the interop easier.

Assuming that we need to calculate the area of each Shape polymorphically.

In C# we would normally create a hypothetical object hierarchy and a Visitor. In this example, we would have to create a ShapeVisitor class and then a derived ShapeAreaCalculator visitor class.

In F#, we can use Pattern Matching on the Shape type:

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
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!