#f#
Вопрос:
У меня есть такой тип союза 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)
Как видно, оба пути почти одинаковы, за исключением конструктора случая объединения.
Может ли это быть написано более общим способом — может быть, даже без необходимости использовать сопоставление шаблонов?
Комментарии:
1. Вероятно, вы могли бы сделать это с помощью размышления. Такой подход вы бы рассмотрели?
2. Да, отражение было бы в порядке
Ответ №1:
Это не очень красиво, но я думаю, что это делает то, что ты хочешь:
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 следует жесткому шаблону, поэтому обработка ошибок невозможна.
Комментарии:
1. Заменил код из вопроса, и все по — прежнему работает. Спасибо!