我看到你可以enforce constructor usage单个案例的歧视联盟,你可以用多案例做同样的事吗?
例如
type MemberId =
| MemberId of int
| MemberGuid of Guid
我目前正在尝试这样的fsi
val create : int -> T option
val create : Guid -> T option
但是我猜测像C#,F#不会允许你根据返回类型重载以进行解包:
val value : T -> string
修改---------------
MemberId.fsi =
module MemberId
open System
type _T
val createId : int -> _T option
val createGuid : Guid -> _T option
val value : _T -> 'a
MemberId.fs =
module MemberId
open System
type _T =
| Id of int
| MemberGuid of Guid
let createId id = match id with
| x when x>0 -> Some(Id(id))
| _ -> None
let createGuid guid = Some(MemberGuid( guid))
let value (e:_T):int = e
看起来非常接近,但是打包器没有编译,我似乎无法弄清楚如何编写它
TestConsumer MemberIdClient.fs =
module MemberIdClient
open System
open MemberId
let address1 = MemberId.create(-1)
let address2 = MemberId.create(Guid.Empty)
let unwrapped1 =
match address1 with
| MemberId x -> () // compilation error on 'MemberId x'
| _ -> ()
答案 0 :(得分:5)
函数不能重载,但方法可以:
type MemberId =
private
| MemberId of int
| MemberGuid of Guid
static member create id = MemberId id
static member create guid = MemberGuid guid
答案 1 :(得分:3)
确实有一种方法可以使用一些内联技巧来重载输出参数:
open System
type MemberId =
private
| MemberId of int
| MemberGuid of Guid
type Create = Create with
static member ($) (Create, id ) = MemberId id
static member ($) (Create, guid) = MemberGuid guid
type Value = Value with
static member ($) (Value, d:int ) = function MemberId id -> id | _ -> failwith "Wrong case"
static member ($) (Value, d:Guid) = function MemberGuid guid -> guid | _ -> failwith "Wrong case"
let inline create x : MemberId = Create $ x
let inline value x : 'IntOrGuid = (Value $ Unchecked.defaultof<'IntOrGuid>) x
let a = create 1
let b = create (Guid.NewGuid())
let c:int = value a
let d:Guid = value b
通过这样做,你可以超载&#39;功能,甚至是输出参数。
无论如何,与单个案例DU的最大区别在于,现在解包器并不安全,这就是为什么解包器没有意义,除非在某些特定场景中。
在这些情况下,您可以考虑其他机制来展开值,例如公开函数isX
或返回可以用活动模式补充的选项来解包。
话虽如此,如果你只对隐藏&#39;构造函数做一些验证,但不隐藏DU你可以简单地遮蔽构造函数,这里有一个例子:
open System
type T =
| MemberId of int
| MemberGuid of Guid
// Shadow constructors
let MemberId x = if x > 0 then Some (MemberId x) else None
let MemberGuid x = Some (MemberGuid x)
let a = MemberId 1
let b = MemberGuid (Guid.NewGuid())
let c = MemberId -1
// but you can still pattern match
let printValue = function
| Some (MemberId x) -> sprintf "case 1, value is %A" x
| Some (MemberGuid x) -> sprintf "case 2, value is %A" x
| None -> "No value"
let ra = printValue a // "case 1, value is 1"
let rb = printValue b // "case 2, value is 67b36c20-2..."
let rc = printValue c // "No value"
// and if you want to use an overloaded constructor
type T with
static member Create id = MemberId id
static member Create guid = MemberGuid guid
let d = T.Create 1
let e = T.Create (Guid.NewGuid())
// or using the inline trick
type Create = Create with
static member ($) (Create, id ) = MemberId id
static member ($) (Create, guid) = MemberGuid guid
let inline create x : T option = Create $ x
let d' = create 1
let e' = create (Guid.NewGuid())
答案 2 :(得分:0)
以下是我需要的Gustavo答案中的一小部分代码,它本身可以单独使用
module MemberId
open System
type MemberId =
| MemberId of int
| MemberGuid of Guid
// Shadow constructors
let MemberId x = if x > 0 then Some (MemberId x) else None
let MemberGuid x = Some (MemberGuid x)