5 people like it.
Like the snippet!
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:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
|
/// strips values of reference types that are null
let denull<'T when 'T : not struct> (x : 'T) =
// some F# core types encode values with null, ignore those
let usesNullAsTrueValue =
if typeof<'T> = typeof<unit> then true
else
let attrs = typeof<'T>.GetCustomAttributes(typeof<CompilationRepresentationAttribute>, false)
if attrs.Length = 0 then false
else
let flags = (attrs.[0] :?> CompilationRepresentationAttribute).Flags
flags.HasFlag CompilationRepresentationFlags.UseNullAsTrueValue
if obj.ReferenceEquals(x, null) && not usesNullAsTrueValue then None
else Some x
// define the option monad
type OptionBuilder() =
member __.Return x = Some x
member __.Bind(x,f) = Option.bind f x
member __.ReturnFrom (x : 'T option) = x
let option = new OptionBuilder()
// example
open Microsoft.Win32
option {
let bkey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
let! k1 = denull <| bkey.OpenSubKey(@"Software\Microsoft\VisualStudio\11.0")
let! k2 = denull <| k1.OpenSubKey(@"DialogPage\Microsoft.VisualStudio.FSharp.Interactive.FsiPropertyPage")
let! switch = denull (k2.GetValue "FsiPreferAnyCPUVersion" :?> string)
if switch = "False" then
return! denull (k2.GetValue "FsiCommandLineArgs" :?> string)
else
return! None
}
|
val denull : x:'T -> 'T option (requires reference type)
Full name: Script.denull
strips values of reference types that are null
val not : value:bool -> bool
Full name: Microsoft.FSharp.Core.Operators.not
val x : 'T (requires reference type)
val usesNullAsTrueValue : bool
val typeof<'T> : System.Type
Full name: Microsoft.FSharp.Core.Operators.typeof
type unit = Unit
Full name: Microsoft.FSharp.Core.unit
val attrs : obj []
Multiple items
type CompilationRepresentationAttribute =
inherit Attribute
new : flags:CompilationRepresentationFlags -> CompilationRepresentationAttribute
member Flags : CompilationRepresentationFlags
Full name: Microsoft.FSharp.Core.CompilationRepresentationAttribute
--------------------
new : flags:CompilationRepresentationFlags -> CompilationRepresentationAttribute
property System.Array.Length: int
val flags : CompilationRepresentationFlags
System.Enum.HasFlag(flag: System.Enum) : bool
type CompilationRepresentationFlags =
| None = 0
| Static = 1
| Instance = 2
| ModuleSuffix = 4
| UseNullAsTrueValue = 8
| Event = 16
Full name: Microsoft.FSharp.Core.CompilationRepresentationFlags
CompilationRepresentationFlags.UseNullAsTrueValue: CompilationRepresentationFlags = 8
type obj = System.Object
Full name: Microsoft.FSharp.Core.obj
System.Object.ReferenceEquals(objA: obj, objB: obj) : bool
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
Multiple items
type OptionBuilder =
new : unit -> OptionBuilder
member Bind : x:'a option * f:('a -> 'b option) -> 'b option
member Return : x:'c -> 'c option
member ReturnFrom : x:'T option -> 'T option
Full name: Script.OptionBuilder
--------------------
new : unit -> OptionBuilder
member OptionBuilder.Return : x:'c -> 'c option
Full name: Script.OptionBuilder.Return
val x : 'c
val __ : OptionBuilder
member OptionBuilder.Bind : x:'a option * f:('a -> 'b option) -> 'b option
Full name: Script.OptionBuilder.Bind
val x : 'a option
val f : ('a -> 'b option)
module Option
from Microsoft.FSharp.Core
val bind : binder:('T -> 'U option) -> option:'T option -> 'U option
Full name: Microsoft.FSharp.Core.Option.bind
member OptionBuilder.ReturnFrom : x:'T option -> 'T option
Full name: Script.OptionBuilder.ReturnFrom
val x : 'T option
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
Multiple items
val option : OptionBuilder
Full name: Script.option
--------------------
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
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