Table of Contents

Operators

open FSharp.Interop.Dynamic auto-opens FSharp.Interop.Dynamic.TopLevelOperators.

? — get or invoke a named member

let length: int = "hello"?Length
let hello: string = "HelloWorld"?Substring(0, 5)

What happens depends on the result type F# infers:

  • If 'TResult is not a function, ? does a DLR get (InvokeGet). "hello"?Length is a property get.
  • If 'TResult is a function, ? returns a callable. "HelloWorld"?Substring has type int * int -> string (or whatever you bind), and applying it does InvokeMember.

That is why target?Foo(1, 2) works as a method call: the application forces a function type.

A void CLR method is an unit-returning function:

let items = ResizeArray<string>()
items?Add("1")

?<- — set a named member

open System.Dynamic
let o = ExpandoObject()
o?Name <- "Ada"

Always a DLR set (InvokeSet). The result is unit.

!? — invoke the target itself

let add = (+)
let add3: int -> int = !?add 3
add3 4  // 7

!? is Dyn.invocation target Direct. Use it on:

  • An F# function boxed as obj
  • A Dynamitey curry: !?Dynamic.Curry(...)?Format("Test {0}")
  • Anything the DLR can Invoke

On a non-callable, both binders fail and you get AggregateException wrapping two RuntimeBinderExceptions.

Named arguments

Dynamitey InvokeArg via Dyn.namedArg:

open Dynamitey
let o = Build<ExpandoObject>.NewObject(Dyn.namedArg "One" 1)

pythonnet:

np?array([| 6.; 5.; 4. |], Dyn.namedArg "dtype" np?int32)

Static members

open System.Linq
let empty: int seq = Dyn.staticTarget<Enumerable> |> Dyn.invokeGeneric "Empty" [typeof<int>] ()

Dyn.staticContext typeof<Foo> is the same thing when you have a Type in hand instead of a type parameter.

Events

poco |> Dyn.memberAddAssign "Event" handler
poco |> Dyn.memberSubtractAssign "Event" handler

That is DLR += / -= on the named member, not F# event syntax.