Tweet

1 people like it.

Like the snippet!

C#-Friendly Single-Case Discriminated Unions

Single-case Discriminated Unions (https://fsharpforfunandprofit.com/posts/designing-with-types-single-case-dus/) are a lightweight way to create types for important concepts in your domain. Unfortunately, there's a few gotchas when consuming from C# to be aware of. For one, if you use the `==` or `!=` operators in C#, it will do a reference comparison, which is almost certainly not what you want for these wrapper types. By overriding `op_Equality` and `op_Inequality`, this will force it to use a structural comparison. Secondly, when using string concatenation via `+`, `String.Format`, or string interpolation, C# will implicitly convert non-string arguments to a string via `ToString`. This means if you forget to use `.Item` to unwrap your value, you will not get a compiler error, it will just implicitly call `ToString`, which by default will look like this: `Id "c148b684-2c40-4383-a1b9-0e8f37752fd0"`. By overriding `ToString`, we can make sure it will look like the raw underlying type when converted to a string: `c148b684-2c40-4383-a1b9-0e8f37752fd0`.

1: 2: 3: 4: 5: 6: type Id = Id of System . Guid with override this . ToString () = let ( Id id ) = this in string id static member op_Equality ( a , b : Id ) = a = b static member op_Inequality ( a , b : Id ) = a <> b

Multiple items

union case Id.Id: System.Guid -> Id



--------------------

type Id =

| Id of Guid

override ToString : unit -> string

static member ( = ) : a:Id * b:Id -> bool

static member ( <> ) : a:Id * b:Id -> bool



Full name: Script.Id

namespace System

Multiple items

type Guid =

struct

new : b:byte[] -> Guid + 4 overloads

member CompareTo : value:obj -> int + 1 overload

member Equals : o:obj -> bool + 1 overload

member GetHashCode : unit -> int

member ToByteArray : unit -> byte[]

member ToString : unit -> string + 2 overloads

static val Empty : Guid

static member NewGuid : unit -> Guid

static member Parse : input:string -> Guid

static member ParseExact : input:string * format:string -> Guid

...

end



Full name: System.Guid



--------------------

System.Guid()

System.Guid(b: byte []) : unit

System.Guid(g: string) : unit

System.Guid(a: int, b: int16, c: int16, d: byte []) : unit

System.Guid(a: uint32, b: uint16, c: uint16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit

System.Guid(a: int, b: int16, c: int16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit

val this : Id

override Id.ToString : unit -> string



Full name: Script.Id.ToString

val id : System.Guid

Multiple items

val string : value:'T -> string



Full name: Microsoft.FSharp.Core.Operators.string



--------------------

type string = System.String



Full name: Microsoft.FSharp.Core.string

val a : Id

val b : Id

More information