对作为选项返回的一次性对象使用样式绑定

时间:2017-01-29 18:19:01

标签: f#

想知道是否有一种优雅的方式来完成以下任务:

我有一个创建Disposable的函数并将其作为Option返回。呼叫者匹配它。现在,由于包装对象绑定在匹配大小写内部,我不知道如何在匹配内部进行“使用”样式绑定,以便对象得到正确处理。

let createSocket (hostEntry:IPHostEntry) =
    let httpPort = 80
    let endpoint = new IPEndPoint(hostEntry.AddressList.[0], httpPort)
    let socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
    socket.Connect(endpoint)
    if (socket.Connected) then Some socket else None

let fetchResource url =
    let uri = new System.Uri(url)
    let hostEntry = Dns.GetHostEntry(uri.Host)
    match createSocket(hostEntry) with
    | Some socket ->
        use s = socket // More elegant way?
        sendRequest s uri.Host uri.PathAndQuery |> getResponse
    | None ->
        "Failed to open socket"

3 个答案:

答案 0 :(得分:6)

你在核心库中有一个using功能,但是你是否认为这更优雅了取决于你:

match createSocket(hostEntry) with
| Some socket ->
    using socket <| fun s ->
        sendRequest s uri.Host uri.PathAndQuery |> getResponse
| None ->
    "Failed to open socket"

您可以更进一步,将整个技巧打包在一个函数中:

module Option =     
    let using func = Option.bind (fun disp -> using disp func)

...

createSocket(hostEntry)
|> Option.using (fun s ->
    sendRequest s uri.Host uri.PathAndQuery |> getResponse)
// handle None however you like
|> function Some x -> x | None -> "Failed to open socket" 

虽然我不记得我曾经觉得有必要亲自这样做。

答案 1 :(得分:4)

我认为null在这里最为优雅。

if socket.Connected then socket else null

...

use s = createSocket(hostEntry)
if s = null then
    "Failed..."
else
    sendRequest...

use可以正确处理(忽略)null。也就是说,我没有找到特别不优雅的原始代码。

答案 2 :(得分:0)

您的问题是createSocket功能本身。在该函数内部,您正在创建Socket,它实现IDisposable,并且您将其移交到外部范围。您应该重构,以便能够利用use socket = new Socket(...)语法。这可以通过创建一个实现IDisposable并正确处理套接字的包装类来完成。