Getting started
Installing
Important
Install 6.0.0 (netstandard2.0 + net10.0). 5.0.1.268 is the previous TFM set (net45 / netstandard1.6 / netstandard2.0).
dotnet add package FSharp.Interop.Dynamic
<PackageReference Include="FSharp.Interop.Dynamic" Version="6.0.0" />
open FSharp.Interop.Dynamic
open FSharp.Interop.Dynamic.Operators // optional: ?+?, ?=?, …
open FSharp.Interop.Dynamic brings in the auto-opened ?, ?<-, and !? operators. The Dyn module is always there; you do not need a second open for it.
The three operators you actually use
| Operator | Meaning |
|---|---|
target?Name |
Get a property, or call a method (the result can be a function you then apply) |
target?Name <- value |
Set a property |
!?target |
Invoke target itself (an F# function boxed as obj, a delegate, a Dynamitey curry) |
open System.Dynamic
let o = ExpandoObject()
o?Name <- "Ada"
let name: string = o?Name
let parts: string[] = "a,b,c"?Split(',')
Annotate the result type when F# cannot infer it. The DLR conversion uses that type.
Why not just use C# dynamic from F#?
You can, with a C# helper, and for a member whose name is a literal in C# that is often simpler. Reach for this library when:
- The call is in F#. There is no
dynamickeyword.?is the F# spelling. - The name is data.
o?Namestill writesNamein source;Dyn.get name otakes a string. - You want F# piping.
target |> Dyn.get "Name",target |> Dyn.tryGet "Name". - You want an option, not an exception.
Dyn.tryGet/Dyn.exists— see tryGet and exists. C#dynamichas no equivalent.
Infer the result, or you get obj
let n: int = "hello"?Length // 5
let boxed = "hello"?Length // obj, because nothing asked for int
Methods that return unit (void in CLR) need that annotation too, or the binder asks for a value from a void member and throws:
let items = ResizeArray<string>()
let _: unit = items?Add("x")
Where to go next
- Why this library — untyped payloads, optional fields, names as data, C#
dynamic - Operators —
?,?<-,!?in detail - Dyn — the functions behind those operators
- tryGet and exists — the issue #27 surface
- Caveats — explicit interface members, AOT, conversion vs missing, 15-arg, optionals, null target