映射到没有模式匹配的 Union Case 构造函数
Map to Union Case constructor without pattern match
我有一个这样的联合类型 CustomerEvent
:
type CustomerRegisteredEvent = { CompanyName: string }
type CustomerDeletedEvent = { DeletedOn: DateTimeOffset }
type CustomerEvent =
| CustomerRegistered of CustomerRegisteredEvent
| CustomerDeleted of CustomerDeletedEvent
我也有一个这样的map
函数:
let map (input: Events.IEvent): CustomerEvent =
match input with
| :? Events.IEvent<CustomerRegisteredEvent> as event ->
CustomerRegistered(event.Data)
| :? Events.IEvent<CustomerDeletedEvent> as event ->
CustomerDeleted(event.Data)
可以看出,除了union case的构造函数不同,两条路径几乎相同
是否可以用更通用的方式编写 - 甚至不必使用模式匹配?
它不是很漂亮,但我认为这可以满足您的要求:
open FSharp.Reflection
let getCaseMap<'t> () =
FSharpType.GetUnionCases(typeof<'t>)
|> Seq.map (fun unionCase ->
let typ =
let property =
unionCase.GetFields() |> Seq.exactlyOne
property.PropertyType
let create data =
FSharpValue.MakeUnion(unionCase, [| data |])
:?> 't
typ.Name, create)
|> Map
let caseMap = getCaseMap<CustomerEvent> ()
let map (input: Events.IEvent) =
let typ =
input.GetType().GenericTypeArguments
|> Seq.exactlyOne
let data =
let property =
input.GetType().GetProperty("Data")
property.GetValue(input)
caseMap.[typ.Name] data
这使用反射来避免模式匹配,而是进行映射查找以直接从给定事件的类型中找到正确的联合案例。它假定 DU 遵循严格的模式,因此没有错误处理。
我有一个这样的联合类型 CustomerEvent
:
type CustomerRegisteredEvent = { CompanyName: string }
type CustomerDeletedEvent = { DeletedOn: DateTimeOffset }
type CustomerEvent =
| CustomerRegistered of CustomerRegisteredEvent
| CustomerDeleted of CustomerDeletedEvent
我也有一个这样的map
函数:
let map (input: Events.IEvent): CustomerEvent =
match input with
| :? Events.IEvent<CustomerRegisteredEvent> as event ->
CustomerRegistered(event.Data)
| :? Events.IEvent<CustomerDeletedEvent> as event ->
CustomerDeleted(event.Data)
可以看出,除了union case的构造函数不同,两条路径几乎相同
是否可以用更通用的方式编写 - 甚至不必使用模式匹配?
它不是很漂亮,但我认为这可以满足您的要求:
open FSharp.Reflection
let getCaseMap<'t> () =
FSharpType.GetUnionCases(typeof<'t>)
|> Seq.map (fun unionCase ->
let typ =
let property =
unionCase.GetFields() |> Seq.exactlyOne
property.PropertyType
let create data =
FSharpValue.MakeUnion(unionCase, [| data |])
:?> 't
typ.Name, create)
|> Map
let caseMap = getCaseMap<CustomerEvent> ()
let map (input: Events.IEvent) =
let typ =
input.GetType().GenericTypeArguments
|> Seq.exactlyOne
let data =
let property =
input.GetType().GetProperty("Data")
property.GetValue(input)
caseMap.[typ.Name] data
这使用反射来避免模式匹配,而是进行映射查找以直接从给定事件的类型中找到正确的联合案例。它假定 DU 遵循严格的模式,因此没有错误处理。