在调用C#代码时,在F#中进行大量空值检查的最佳方法是什么

时间:2017-06-12 14:27:34

标签: f# functional-programming

我想知道以功能方式与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

但我对此并不满意。这样做的功能方法是什么?我想也许一些计算表达式会有所帮助,但我不知道如何完成。

2 个答案:

答案 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#函数中,我们假设AuthenticationIdentity属性的非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#大约两三周,所以这可能完全是愚蠢的:)