Caveats
Explicit interface members
The DLR cannot see members implemented explicitly on an interface. Neither can ?, Dyn.get, or C# dynamic. If you need that member, call it through the interface type in ordinary F#.
Conversion vs missing
RuntimeBinderException means the binder could not do what you asked. That is not always "the member is missing":
- Missing property → binder exception →
tryGetreturnsNone - Present property, wrong
'T→ conversion / unbox failure → throws,tryGetdoes not swallow it - Void method inferred as a value → binder exception
Annotate 'T / unit so the binder and the conversion agree.
A present null exists
Dyn.exists "x" is true if InvokeGet succeeded, including when the value is null. tryGet returns Some null for a reference type. That is different from missing.
Null target
Dyn.tryGet on a null target is None. Dyn.exists is false. That is the same answer as a missing member. Dyn.set on a null target still throws NullReferenceException. A present null value is still Some null / exists true.
More than 14 arguments
On 6.0.0 a call with 15 or more arguments threw TypeLoadException: Cannot Emit long delegates without ImpromptuInterface installed. Fourteen arguments worked. Dynamitey 3.0.3 never declared the package that path needed. Dynamitey.Community 4.0.0 builds that call site, and 7.0.0 takes that package.
C# optional parameters
The DLR does not fill CLR optional defaults. obj?Opt(5) and obj?Opt(Dyn.namedArg "a" 5) both fail (No overload takes 1 arguments) when Opt is Opt(int a, int b = 0). Dyn.namedArg only builds an InvokeArg; the miss is on the call. Pass every argument. Named args work when the full set is present.
Function-typed results delay the call
If F# infers 'TResult as a function, ? / Dyn.get / Dyn.invokeMember return a callable. A missing member in that mode used to look like Some (fun …) until you applied it. tryGet does InvokeGet first, so a missing member is None even when 'T is a function.
Explicit interface and COM
COM and IDynamicMetaObjectProvider objects can succeed on names that reflection does not list. Existence checks go through InvokeGet, not GetMemberNames.
Trimming and NativeAOT
This library is DLR-based. It is not trim-safe or NativeAOT-safe. Members it resolves at runtime can be removed by the trimmer. Do not publish a trimmed consumer and expect ? to keep working.
Historical .NET Core 2.0.0–2.0.2 bug
Nested classes inside generic classes broke C# dynamic (substring argument-length exceptions). .NET Core 2.0.3+ and every current TFM this package ships are fine. Recorded as #11.
Security
Member names are capabilities. Do not build ? / Dyn.get / Dyn.invokeMember names from untrusted input. See SECURITY.md.