我想知道以功能方式与F#中的C#代码交互的最佳方式,当我必须多次检查null时。
从C#开始,很简单,因为我有空操作符
public bool Authorize(DashboardContext dashboardContext)
{
var context = new OwinContext(dashboardContext.GetOwinEnvironment());
var user = context.Authentication.User;
return user?.Identity?.IsAuthenticated ?? false;
}
从F#,我做了这个
let authorize (ctx:DashboardContext) =
match OwinContext(ctx.GetOwinEnvironment()) with
| null -> false
| c -> match c.Authentication.User with
| null -> false
| user -> user.Identity.IsAuthenticated
但我对此并不满意。这样做的功能方法是什么?我想也许一些计算表达式会有所帮助,但我不知道如何完成。
答案 0 :(得分:9)
Option.ofObj
会将可以为空的对象转换为Option
。然后,您可以使用Option
模块中已定义的帮助程序。例如,您在那里写的部分模式已经被Option.bind
封装。
let authorize (ctx:DashboardContext) =
ctx.GetOwinEnvironment() |> OwinContext |> Option.ofObj
|> Option.bind (fun c -> c.Authentication.User |> Option.ofObj)
|> Option.map (fun user -> user.Identity.IsAuthenticated)
|> Option.defaultValue false
Option.bind
使用Option<'a>
和一个采用'a
类型的函数并返回Option<'a>
。当它在管道中使用时,它是一种映射&#34;的方式。 Some
或将其过滤为None
。
我会说你写的这个函数实际上看起来很好,但是这种方式可能被认为是更惯用的,尽管在这个例子中它可能有点难以理解。 Option.bind
在保存多层嵌套时真正发挥作用。
值得注意的是,在您的F#函数和我的F#函数中,我们假设Authentication
和Identity
属性的非null,并且在访问其属性时冒着空引用异常的风险。这与使用空传播的C#方法形成对比。目前还没有一种内置的方法可以在F#中实现这一点,但可能有一些先进的方法来模拟它。
也可以使用计算表达式来完成此操作。请参阅MaybeBuilder
here。
答案 1 :(得分:0)
我喜欢 TheQuickBrownFox 使用Option.ofObj
的想法,但是我仍然发现使用内置函数编写代码很乏味,因此我编写了一个自定义运算符来链接空检查:
let inline (>>?) f g = f >> Option.bind (g >> Option.ofObj)
使用此运算符,C#中的内容将是
user?.Identity?.IsAuthenticated ?? false
成为:
user
|> (Option.ofObj
>>? (fun x -> x.Identity)
>>? (fun x -> x.IsAuthenticated)
>> Option.defaultValue false)
哪个更漂亮!
免责声明:我总共使用F#大约两三周,所以这可能完全是愚蠢的:)