tryGet and exists
#27: unstructured objects, check o?myProp without eating a RuntimeBinderException.
These ship on Dynamitey 3.0.3. They do not need Dynamitey 4.0.0.
Dyn.tryGet
open System.Dynamic
open FSharp.Interop.Dynamic
let o = ExpandoObject()
o?myProp <- "hi"
let present: string option = o |> Dyn.tryGet "myProp" // Some "hi"
let missing: string option = o |> Dyn.tryGet "nope" // None
Lookup is Dynamic.InvokeGet only. Then the existing conversion / callable wrapping runs outside the catch.
| Situation | Result |
|---|---|
| Member missing | None |
Member present, value converts to 'T |
Some value |
| Member present, value is null | Some null (for a reference 'T) |
Member present, value cannot convert to 'T |
throws (InvalidCastException or a binder exception) — not None |
Member missing, 'T is a function type |
None immediately (does not return a lazy callable) |
| Getter throws something else | that exception propagates |
Dyn.exists
o |> Dyn.exists "myProp" // true
o |> Dyn.exists "nope" // false
True when InvokeGet succeeds. A present null is still present. A throwing getter is not reported as missing.
exists does not convert the value. That is the difference from tryGet >> Option.isSome when conversion would fail: exists can be true while tryGet as int throws.
Do not use GetMemberNames for this
Dynamitey exposes Dynamic.GetMemberNames. It lists names; it is not the same test as o?myProp. COM, some IDynamicMetaObjectProvider implementations, and binder tricks can succeed on a get whose name is not in that list. tryGet / exists use the same InvokeGet as ?.