如何将以下使用c#HtmlAgility库的代码转换为优雅的样式?
if node <> null then
let nodes = node.SelectNodes("//input[@name='xxx']")
if nodes <> null then
let first = nodes.[0]
if first <> null then
let value = first.Attributes.["value"]
if value <> null then
Some value.Value
else
None
else
None
else
None
else
None
Run Code Online (Sandbox Code Playgroud)
以下代码可能有用吗?但是,它仍然不像C#6的?.运营商那样简洁.
let toOpt = function null -> None | x -> Some x
node |> toOpt
|> Option.map (fun x -> x.SelectNodes("//input[@name='xxx']"))
|> Option.map (fun x -> x.[0] )
|> Option.map (fun x -> x.Attributes.["value"] )
|> Option.map (fun x -> x.Value )
Run Code Online (Sandbox Code Playgroud)
C#6版本仍然更加简洁:
node?.SelectNodes("//input[@name='xxx']")[0]?.Attributes["value"]?.Value
Run Code Online (Sandbox Code Playgroud)
可以Option.bind帮忙吗?
Jus*_*mer 11
仅供参考F#4 Option.ofObj
在F#中null有充分理由避免使用.处理依赖null我的一般建议的C#库时,将在该库上提供一个F#惯用的"适配器".
在实践中,这可能是相当多的工作,结果可能不像C#操作符那样简洁?.(不论是否这样的操作符是一个好主意).
据我所知,F#编译器不支持这样的运算符,但是如果你对它有强烈的感觉,你应该在http://fslang.uservoice.com/上提出它.F#社区很友好,但我怀疑你必须非常积极地争论才能说服社区,这对F#来说是个好主意.
与此同时; 让它稍微简洁的一种方法是创建一个像这样的计算表达式(这getAttributeValue是你的代码看起来像):
// Basically like the classic `maybe` monad
// but with added support for nullable types
module Opt =
let inline Return v : Option<'T> = Some v
let inline ReturnFrom t : Option<'T> = t
let inline ReturnFrom_Nullable ot : Option<'T> =
match ot with
| null -> None
| _ -> Some ot
let inline Bind (ot : Option<'T>) (fu : 'T -> Option<'U>) : Option<'U> =
match ot with
| None -> None
| Some vt ->
let ou = fu vt
ou
let inline Bind_Nullable (vt : 'T) (fu : 'T -> Option<'U>) : Option<'U> =
match vt with
| null -> None
| _ ->
let ou = fu vt
ou
let Delay ft : Option<'T> = ft ()
type OptBuilder() =
member inline x.Return v = Return v
member inline x.ReturnFrom v = ReturnFrom v
member inline x.ReturnFrom v = ReturnFrom_Nullable v
member inline x.Bind (t, fu) = Bind t fu
member inline x.Bind (t, fu) = Bind_Nullable t fu
member inline x.Delay ft = Delay ft
let inline ofObj o =
match o with
| null -> None
| _ -> Some o
open HtmlAgilityPack
let opt = Opt.OptBuilder()
let getAttributeValue (node : HtmlNode) (path : string) : string option =
opt {
let! nodes = node.SelectNodes path
let! node = nodes.[0]
let! attr = node.Attributes.["value"]
return! attr.Value
}
let html = """
<html>
<title>Hello</title>
<body>Yellow <div name='Test' value='Stone'>Div</div></title>
</html>
"""
[<EntryPoint>]
let main argv =
let doc = HtmlDocument ()
doc.LoadHtml html
let r = getAttributeValue doc.DocumentNode "//div[@name='Test']"
printfn "Result: %A" r
0
Run Code Online (Sandbox Code Playgroud)
你可以在 Fsharpx 中使用可能的 monad
maybe {
let! node = toOpt node
let! nodes = toOpt node.SelectNodes("")
let! first = toOpt nodes.[0]
let! value = toOpt first.Attributes.["value"]
return value.Value
}
Run Code Online (Sandbox Code Playgroud)
这将导致None如果任何一个为空,或者Some value.Value如果不是。
注意如果你通读一遍,FuleSnabel 的解决方案实际上更好,因为它可以让你摆脱toOpt无处不在的东西,你可以让它成为
opt {
let! node = node
let! nodes = node.SelectNodes("")
let! first = nodes.[0]
let! value = first.Attributes.["value"]
return value.Value
}
Run Code Online (Sandbox Code Playgroud)
选择这个的唯一原因是,如果您真的只想将您的项目限制为 Fsharpx 中定义的标准工作流构建器,而不是定义您自己的自定义工作流构建器(您可以从该答案中复制和粘贴)。
| 归档时间: |
|
| 查看次数: |
2278 次 |
| 最近记录: |