I've not been able to find a robust, general op_Dynamic implementation: can anyone point me to one? So far searches have only turned up toys or specific purpose implementations, but I'd like to have one on hand which, say, compares in robustness to C#'s default static dynamic implementation (i.e. handle lots / all cases, cache reflection calls) (it's been a while since I've looked at C#'s static d开发者_如何学Goynamic, so forgive me if my assertions about it's abilities are false).
Thanks!
There is a module FSharp.Interop.Dynamic, on nuget that should robustly handle the dynamic operator using the dlr.
It has several advantages over a lot of the snippets out there.
- Performance it uses Dynamitey for the dlr call which implements caching and is a .NET Standard Library
- Handles methods that return void, you'll get a binding exception if you don't discard results of those.
- The dlr handles the case of calling a delegate return by a function automatically, this will also allow you to do the same with an FSharpFunc
Adds an !? prefix operator to handle invoking directly dynamic objects and functions you don't have the type at runtime.
It's open source, Apache license, you can look at the implementation and it includes unit test example cases.
You can never get fully general implementation of the ?
operator. The operator can be implemented differently for various types where it may need to do something special depending on the type:
- For
Dictionary<T, R>
, you'd want it to use the lookup function of the dictionary - For the SQL objects in my article you referenced, you want it to use specific SQL API
- For unknown .NET objects, you want it to use .NET Reflection
If you're looking for an implementation that uses Reflection, then you can use one I implemented in F# binding for MonoDevelop (available on GitHub). It is reasonably complete and handles property access, method calls as well as static members. (The rest of the linked file uses it heavily to call internal members of F# compiler). It uses Reflection directly, so it is quite slow, but it is quite feature-complete.
Another alternative would be to implement the operator on top of .NET 4.0 Dynamic Language Runtime (so that it would use the same underlying API as dynamic
in C# 4). I don't think there is an implementation of this somewhere out there, but here is a simple example how you can get it:
#r "Microsoft.CSharp.dll"
open System
open System.Runtime.CompilerServices
open Microsoft.CSharp.RuntimeBinder
let (?) (inst:obj) name (arg:'T) : 'R =
// Create site (representing dynamic operation for converting result to 'R
let convertSite =
CallSite<Func<CallSite, Object, 'R>>.Create //'
(Binder.Convert(CSharpBinderFlags.None, typeof<'R>, null)) //'
// Create site for the method call with single argument of type 'T
let callSite =
CallSite<Func<CallSite, Object, 'T, Object>>.Create //'
(Binder.InvokeMember
( CSharpBinderFlags.None, name, null, null,
[| CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) |]))
// Run the method and perform conversion
convertSite.Target.Invoke
(convertSite, callSite.Target.Invoke(callSite, inst, arg))
let o = box (new Random())
let a : int = o?Next(10)
This works only for instance method calls with single argument (You can find out how to do this by looking at code generated by C# compiler for dynamic
invocations). I guess if you mixed the completeness (from the first one) with the approach to use DLR (in the second one), you'd get the most robust implementation you can get.
EDIT: I also posted the code to F# Snippets. Here is the version using DLR: http://fssnip.net/2U and here is the version from F# plugin (using .NET Reflection): http://fssnip.net/2V
精彩评论