5 people like it.

Preempting NullReferenceExceptions

When interfacing .NET libraries that potentially yield null values, a lot of boilerplate code is required to ensure no NullReferenceExceptions are raised. This is an attempt to avoid such repetition with computation expressions.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
/// strips values of reference types that are null
let strip<'T when 'T : null> (x : 'T) = match x with null -> None | x -> Some x

type DenullBuilder() =
    member __.Return x = x
    member __.Zero() = null
    member __.Bind(x, f) = match x with null -> null | x -> f x


let denull = new DenullBuilder()

// example
open Microsoft.Win32

denull {
    let bkey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
    let! k1 = bkey.OpenSubKey(@"Software\Microsoft\VisualStudio\11.0")
    let! k2 = k1.OpenSubKey(@"DialogPage\Microsoft.VisualStudio.FSharp.Interactive.FsiPropertyPage")
    let! switch = k2.GetValue "FsiPreferAnyCPUVersion" :?> string

    if switch = "True" then
        return k2.GetValue "FsiCommandLineArgs" :?> string
} |> strip
val strip : x:'T -> 'T option (requires 'T : null)

Full name: Script.strip


 strips values of reference types that are null
val x : 'T (requires 'T : null)
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
Multiple items
type DenullBuilder =
  new : unit -> DenullBuilder
  member Bind : x:'a * f:('a -> 'b) -> 'b (requires 'a : null and 'b : null)
  member Return : x:'d -> 'd
  member Zero : unit -> 'c (requires 'c : null)

Full name: Script.DenullBuilder

--------------------
new : unit -> DenullBuilder
member DenullBuilder.Return : x:'d -> 'd

Full name: Script.DenullBuilder.Return
val x : 'd
val __ : DenullBuilder
member DenullBuilder.Zero : unit -> 'c (requires 'c : null)

Full name: Script.DenullBuilder.Zero
member DenullBuilder.Bind : x:'a * f:('a -> 'b) -> 'b (requires 'a : null and 'b : null)

Full name: Script.DenullBuilder.Bind
val x : 'a (requires 'a : null)
val f : ('a -> 'b) (requires 'a : null and 'b : null)
val denull : DenullBuilder

Full name: Script.denull
namespace Microsoft
namespace Microsoft.Win32
val bkey : RegistryKey
type RegistryKey =
  inherit MarshalByRefObject
  member Close : unit -> unit
  member CreateSubKey : subkey:string -> RegistryKey + 4 overloads
  member DeleteSubKey : subkey:string -> unit + 1 overload
  member DeleteSubKeyTree : subkey:string -> unit + 1 overload
  member DeleteValue : name:string -> unit + 1 overload
  member Dispose : unit -> unit
  member Flush : unit -> unit
  member GetAccessControl : unit -> RegistrySecurity + 1 overload
  member GetSubKeyNames : unit -> string[]
  member GetValue : name:string -> obj + 2 overloads
  ...

Full name: Microsoft.Win32.RegistryKey
RegistryKey.OpenBaseKey(hKey: RegistryHive, view: RegistryView) : RegistryKey
type RegistryHive =
  | ClassesRoot = -2147483648
  | CurrentUser = -2147483647
  | LocalMachine = -2147483646
  | Users = -2147483645
  | PerformanceData = -2147483644
  | CurrentConfig = -2147483643
  | DynData = -2147483642

Full name: Microsoft.Win32.RegistryHive
field RegistryHive.CurrentUser = -2147483647
type RegistryView =
  | Default = 0
  | Registry64 = 256
  | Registry32 = 512

Full name: Microsoft.Win32.RegistryView
field RegistryView.Default = 0
val k1 : RegistryKey
RegistryKey.OpenSubKey(name: string) : RegistryKey
RegistryKey.OpenSubKey(name: string, permissionCheck: RegistryKeyPermissionCheck) : RegistryKey
RegistryKey.OpenSubKey(name: string, writable: bool) : RegistryKey
RegistryKey.OpenSubKey(name: string, permissionCheck: RegistryKeyPermissionCheck, rights: System.Security.AccessControl.RegistryRights) : RegistryKey
val k2 : RegistryKey
val switch : string
RegistryKey.GetValue(name: string) : obj
RegistryKey.GetValue(name: string, defaultValue: obj) : obj
RegistryKey.GetValue(name: string, defaultValue: obj, options: RegistryValueOptions) : obj
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string

More information

Link:http://fssnip.net/fG
Posted:4 years ago
Author:Eirik Tsarpalis
Tags: nullable types , computation expressions