寻找健壮,通用的op_Dynamic实现

时间:2011-02-20 14:41:09

标签: f#

我无法找到一个强大的,通用的op_Dynamic实现:任何人都可以指向一个吗?到目前为止,搜索只出现了玩具或特定用途的实现,但我想有一个,比如说,比较强健性与C#的默认静态动态实现(即处理批次/所有情况,缓存反射调用)(它是我已经看过C#的静态动态了一段时间,所以请原谅我,如果我对它的能力的断言是错误的话。

谢谢!

2 个答案:

答案 0 :(得分:9)

在nuget上有一个模块FSharp.Interop.Dynamic,它应该使用dlr强大地处理动态运算符。

与许多片段相比,它有几个优势。

  • 使用Dynamitey进行实现缓存的dlr调用并且是.NET标准库的性能
  • 处理返回void的方法,如果你不丢弃那些结果,你将得到一个绑定异常。
  • dlr处理由函数自动调用委托返回的情况,这也允许你对FSharpFunc执行相同的操作
  • 添加!?前缀运算符,用于处理直接调用动态对象和在运行时没有类型的函数。

    这是开源的Apache许可证,您可以查看implementation,其中包含单元测试example cases

答案 1 :(得分:8)

您永远无法完全实现?运算符。对于可能需要根据类型执行某些特殊操作的各种类型,可以以不同的方式实现运算符:

  • 对于Dictionary<T, R>,您希望它使用字典的查找功能
  • 对于您引用的文章中的SQL对象,您希望它使用特定的SQL API
  • 对于未知的.NET对象,您希望它使用.NET Reflection

如果您正在寻找使用Reflection的实现,那么您可以使用我在F#绑定中为MonoDevelop(available on GitHub)实现的实现。它相当完整,处理属性访问,方法调用以及静态成员。 (链接文件的其余部分大量使用它来调用F#编译器的内部成员)。它直接使用Reflection,因此速度很慢,但功能完备。

另一种替代方法是在.NET 4.0动态语言运行时之上实现运算符(以便它在C#4中使用与dynamic相同的底层API)。我不认为在某处有一个实现,但这是一个简单的例子,你可以得到它:

#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)

这仅适用于具有单个参数的方法调用(您可以通过查看C#编译器为dynamic调用生成的代码来了解如何执行此操作)。我想如果你把完整性(从第一个)和使用DLR的方法混合在一起(在第二个方面),你将获得最强大的实现。

编辑:我还将代码发布到了F#Snippets。以下是使用DLR的版本:http://fssnip.net/2U,这是F#插件的版本(使用.NET Reflection):http://fssnip.net/2V