jbt*_*ule 22 null f# null-coalescing-operator null-coalescing
在与C#库交互时,我发现自己想要Nullable结构和引用类型的C#的空合并运算符.
是否有可能在F#中使用一个内联适当if情况的重载运算符对其进行近似?
jbt*_*ule 27
是的,使用在这个SO答案" F#中的重载运算符 "中找到的一些小的hackery .
在编译时,可以内联使用任一个('a Nullable, 'a) ->'a或('a when 'a:null, 'a) -> 'a单个运算符的正确重载.甚至('a option, 'a) -> 'a可以投入更多的灵活性.
为了给c#操作符提供更接近的行为,我已经设置了默认参数,'a Lazy因此除非原始值是,否则不会调用它的源null.
例:
let value = Something.PossiblyNullReturned()
|?? lazy new SameType()
Run Code Online (Sandbox Code Playgroud)
执行:
NullCoalesce.fs [ Gist ]:
//https://gist.github.com/jbtule/8477768#file-nullcoalesce-fs
type NullCoalesce =
static member Coalesce(a: 'a option, b: 'a Lazy) =
match a with
| Some a -> a
| _ -> b.Value
static member Coalesce(a: 'a Nullable, b: 'a Lazy) =
if a.HasValue then a.Value
else b.Value
static member Coalesce(a: 'a when 'a:null, b: 'a Lazy) =
match a with
| null -> b.Value
| _ -> a
let inline nullCoalesceHelper< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Coalesce : ^a * ^b -> ^c)> a b =
// calling the statically inferred member
((^t or ^a) : (static member Coalesce : ^a * ^b -> ^c) (a, b))
let inline (|??) a b = nullCoalesceHelper<NullCoalesce, _, _, _> a b
Run Code Online (Sandbox Code Playgroud)
或者,我创建了一个利用这种技术的库以及用于处理Null/Option/Nullables的计算表达式,称为FSharp.Interop.NullOptAble
它使用运算符|?->代替.
//https://gist.github.com/tallpeak/7b8beacc8c273acecb5e
open System
let inline isNull value = obj.ReferenceEquals(value, null)
let inline isDBNull value = obj.ReferenceEquals(value, DBNull.Value)
type NullCoalesce =
static member Coalesce(a: 'a option, b: 'a Lazy) = match a with Some a -> a | _ -> b.Value
static member Coalesce(a: 'a Nullable, b: 'a Lazy) = if a.HasValue then a.Value else b.Value
//static member Coalesce(a: 'a when 'a:null, b: 'a Lazy) = match a with null -> b.Value | _ -> a // overridden, so removed
static member Coalesce(a: DBNull, b: 'b Lazy) = b.Value //added to support DBNull
// The following line overrides the definition for "'a when 'a:null"
static member Coalesce(a: obj, b: 'b Lazy) = if isDBNull a || isNull a then b.Value else a // support box DBNull
let inline nullCoalesceHelper< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Coalesce : ^a * ^b -> ^c)> a b =
((^t or ^a) : (static member Coalesce : ^a * ^b -> ^c) (a, b))
Run Code Online (Sandbox Code Playgroud)
用法:
let inline (|??) a b = nullCoalesceHelper<NullCoalesce, _, _, _> a b
let o = box null
let x = o |?? lazy (box 2)
let y = (DBNull.Value) |?? lazy (box 3)
let z = box (DBNull.Value) |?? lazy (box 4)
let a = None |?? lazy (box 5)
let b = box None |?? lazy (box 6)
let c = (Nullable<int>() ) |?? lazy (7)
let d = box (Nullable<int>() ) |?? lazy (box 8)
Run Code Online (Sandbox Code Playgroud)