28

更具体地说,委托具有作为 F# 中的第一类值所没有的功能的特征(如果有的话)是什么?C# 中的委托没有哪些作为一流值起作用的特征(如果有的话)?

4

2 回答 2

31

Delegates 和 F#“First class function values”是完全不同的。

委托是 CLR 的一种机制,是函数-指针+对象对的类型安全包装器(例如方法,-指针this与方法地址一起被捕获)。

另一方面,F# 函数值是抽象类的实现(它曾经在 F# 正式发布之前FSharpFunc<,>被调用)。FastFunc<,>调用通过普通的虚拟方法进行,这比委托调用要快得多。这就是 F# 团队一开始没有使用委托的原因。

因此,如果您可以通过抽象类/虚拟方法将函数“实现”为第一类值,那么微软为什么要添加委托呢?

  • 没有其他选择在 .NET 1.0/1.1 中,没有泛型,因此您必须为要使用的每个函数签名定义一个新的委托类型 (="function type")。
  • (不,仅使用 Java 中的接口不算数。:-P)

好的,但是我们从 .NET 2.0 开始就有泛型,为什么我们仍然有委托?为什么我们不能只使用Func<,>andAction<>来做所有事情?

  • 向后兼容性
  • 多播代表代表可以链接在一起形成新的代表。此机制用于在 VB.NET 和 C# 中实现事件。在幕后,一个事件实际上只是一个委托字段。使用+=语法,您基本上将您的事件处理程序委托添加到事件字段中的委托链中。

除了事件之外,是否有理由使用委托FSharpFunc<,>

FSharpFunc<,>是的,一个:包含 lambda-expressions* 的每个实现都是一个新类。在 .NET 中,类被编码在已编译程序集的元数据中。另一方面,代表不需要额外的元数据。委托类型可以,但实例化这些委托类型在元数据方面是免费的。

但是等等,C# lambda 表达式/匿名方法不是也被实现为隐藏类吗?

是的,C# lambda 是两全其美的 ^^

于 2010-10-09T20:02:11.870 回答
7

我只是想补充一点,SealedSun 的这句话是不正确的:

调用通过普通的虚拟方法进行,这比委托调用要快得多。这就是 F# 团队一开始没有使用委托的原因。

F# 函数并不比委托调用快,也许早在 .NET 1.0 中就是这种情况,但现在委托调用和调用虚拟方法几乎相当。

与调用委托相比,调用编译器无法静态绑定的 F# 函数也非常慢。

open System
open System.Diagnostics

let time name f = 
  let sw = new Stopwatch()
  sw.Start()
  f()
  sw.Stop()
  printfn "%s: %dms" name sw.ElapsedMilliseconds

time "delegate call" (
  fun () ->
    let f = 
      new Func<int, int, int>(
        fun i1 i2 -> 
          let y = i1 + i2
          let x = y + i1
          let z = x + y + i2
          z + x + y + i1
      )

    let mutable r = 0
    for i = 0 to 10000000 do
      r <- f.Invoke(i, i)
)

let f i1 i2 = 
  let y = i1 + i2
  let x = y + i1
  let z = x + y + i2
  z + x + y + i1

time "fsharp func (static bound)" (
  fun () ->
    let mutable r = 0
    for i = 0 to 10000000 do
      r <- f i i
)

let make f =
  let mutable r = 0
  for i = 0 to 10000000 do
    r <- f i i

time "fsharp func (dynamic bound)" (
  fun () -> make f
)

Console.ReadLine() |> ignore

在我的电脑上产生以下结果

delegate call: 65ms
fsharp func (staticly linked): 4ms
fsharp func (dynamic invoke): 356ms
于 2010-10-17T19:47:29.533 回答