这个问题有点宽泛,但我会尝试一下。
让我们从类型开始。我们的消息将有类型和内容。您可以添加更多字段,例如messageId
, sender
, receiver
, etc.
type MessageType = MessageType of string
type Message<'T> = {
messageType : MessageType
message : 'T
}
类似地,我们的处理程序类型将类型和处理程序函数配对。
type HandlerResult = Result<string, string>
type MessageHandler<'T> = {
messageType : MessageType
handlerF : Message<'T> -> HandlerResult
}
我们希望有一个地方可以注册所有处理程序及其类型。字典是理想的选择,因为它速度很快:
let Handlers = System.Collections.Generic.Dictionary<MessageType, MessageHandler<obj>>()
唯一的事情是字典不能有泛型类型,所以这里的所有处理程序都将是类型MessageHandler<obj>
。因此我们需要能够转换<'T>
消息和处理程序<obj>
消息和处理程序并返回。这里我们有一个辅助函数:
let ofMessageGen (msg: Message<obj>) : Message<_> = {
messageType = msg.messageType
message = unbox msg.message
}
以及一个将处理函数注册为<obj>
处理程序:
let registerHandler (handlerF:Message<'T> -> HandlerResult) =
let handler = {
messageType = MessageType <| (typeof<'T>).FullName
handlerF = ofMessageGen >> handlerF
}
Handlers.Add(handler.messageType, handler )
这样我们就可以为任何类型注册处理程序:
registerHandler (fun msg -> sprintf "String message: %s" msg.message |> Ok )
registerHandler (fun msg -> sprintf "int message: %d" msg.message |> Ok )
registerHandler (fun msg -> sprintf "float message: %f" msg.message |> Ok )
这是我们的通用消息处理程序:
let genericHandler (msg:Message<obj>) : HandlerResult =
match Handlers.TryGetValue msg.messageType with
| false, _ -> Error <| sprintf "No Handler for message: %A" msg
| true , handler -> handler.handlerF msg
创建消息:
let createMessage (m:'T) = {
messageType = MessageType <| (typeof<'T>).FullName
message = box m
}
并像这样测试它:
createMessage "Hello" |> genericHandler |> printfn "%A"
createMessage 123 |> genericHandler |> printfn "%A"
createMessage 123.4 |> genericHandler |> printfn "%A"
createMessage true |> genericHandler |> printfn "%A"
// Ok "String message: Hello"
// Ok "int message: 123"
// Ok "float message: 123.400000"
// Error
// "No Handler for message: {messageType = MessageType "System.Boolean";
// message = true;}"