如何在F#中实现null-safe运算符

Pet*_*ner 4 f# exception-handling operator-overloading quotations nullreferenceexception

我想知道你是否可以在F#中添加类似"null-safe"-operator的东西.我知道可能有计划在C#中为这样一个运营商提供下一个更大的版本.

如果没有办法实现这样的行为,是否有办法包装一个可能会抛出一个NullReferenceException捕获异常并返回的块的语句null.

我想到了类似的东西:

let sth = %% <@ someobject.method().another().andAnother() @>
Run Code Online (Sandbox Code Playgroud)

其中%%是执行表达式并检查异常的自定义运算符.

我做的一个尝试是:

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

let (~%%) (right:Expr) =
  try 
    right.CompileUntyped()
    right()
  with
  | ex -> null
Run Code Online (Sandbox Code Playgroud)

但这不符合我的要求(事实上它甚至没有编译:)

我通读了:

有没有人有想法如何优雅地为链式方法创建这样的单行try-catch?

Tom*_*cek 5

我不认为你可以.?用一种实用的,语法上方便的方式为C#实现类似C#的操作符,作为库的一个特性.虽然,我认为这将是一个非常有用的语言扩展,所以我将它提交给F#用户语音,并可能提交拉取请求 :-).

异常处理.您的代码示例与C#完全不同,因为您只是处理任意异常.C#功能的要点是它在每次之后插入 null检查.- 你可以通过转换引号然后编译它来做到这一点,但编译会很慢.你的功能可能只是:

let orNull f = try f () with :? NullReferenceException -> null
Run Code Online (Sandbox Code Playgroud)

然后你就可以写了

orNull <| fun () -> x.Foo().Bar()
Run Code Online (Sandbox Code Playgroud)

..但如前所述,这只是将代码包装在标准try块中并处理异常,因此它不会像C#代码那样做.

计算生成器.如果你想要一个更好的F#解决方案,你可以想出一个计算表达式构建器,它允许你写这样的东西:

safe { let! a = x.Foo()
       let! b = a.Bar()
       return b }
Run Code Online (Sandbox Code Playgroud)

这可以像C#.?操作符一样进行空检查,但是您需要为方法调用链的每个部分单独绑定,因此它需要更多的输入.计算构建器在Bind成员中插入隐藏的空检查,如下所示:

type NullBuilder() = 
  member x.Return(v) = v
  member x.Bind(v, f) = if (box v) = null then null else f v 

let safe = NullBuilder()
Run Code Online (Sandbox Code Playgroud)