Table of Contents

Getting started

Installing

Important

Install 7.0.0 (netstandard2.0 + net10.0, Dynamitey.Community 4.0.0). This is the last release that supports .NET Standard 2.0, which is .NET Framework 4.6.1 through 4.8.1. 6.0.0 was the same target frameworks on Dynamitey 3.0.3. 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="7.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 dynamic keyword. ? is the F# spelling.
  • The name is data. o?Name still writes Name in source; Dyn.get name o takes 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# dynamic has 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