В чем разница между делегатами в C # и функциями в качестве значений первого класса в F #? - PullRequest
27 голосов
/ 09 октября 2010

Точнее, каковы характеристики (если таковые имеются), которые делегаты имеют, которые функции как значения первого класса в F # не имеют; и каковы характеристики, которые функции в качестве значений первого класса имеют (если таковые имеются), которые делегаты в C # не имеют?

Ответы [ 2 ]

29 голосов
/ 10 октября 2010

Делегаты и F # «Значения функций первого класса» совершенно разные.

Делегаты - это механизм CLR, типобезопасной оболочки вокруг пар функция-указатель + объект (например, методы, указатель this захватывается вместе с адресом метода).

Значения функции F #, с другой стороны, являются реализацией абстрактного класса FSharpFunc<,> (раньше он назывался FastFunc<,> до официального выпуска F #). Вызов происходит через обычные виртуальные методы, что намного быстрее, чем вызов делегата. По этой причине команда F # не использовала делегатов.

Итак, если вы можете «реализовать» функции в качестве значений первого класса с помощью абстрактных классов / виртуальных методов, почему Microsoft добавила делегатов?

  • Альтернативы не было В .NET 1.0 / 1.1 не было обобщений, поэтому вам приходилось определять новый тип делегата (= "тип функции") для каждой сигнатуры функции, которую вы хотите использовать.
  • (Нет, просто использование интерфейсов, как в Java, не считается. :-P)

Хорошо, но у нас есть Generics начиная с .NET 2.0, почему у нас все еще есть делегаты? Почему мы не можем просто использовать Func<,> и Action<> для всего?

  • Обратная совместимость
  • Многоадресные делегаты Делегаты могут быть объединены в цепочки для формирования новых делегатов. Этот механизм используется для реализации событий в VB.NET и C #. За кулисами событие на самом деле представляет собой только одно делегатское поле. Используя синтаксис +=, вы по существу добавляете свой обработчик-делегат события в цепочку делегатов в поле события.

Помимо событий, есть ли причина использовать делегатов более FSharpFunc<,>

Да, один: каждая реализация FSharpFunc<,>, которая включает в себя лямбда-выражения *, является новым классом. А в .NET классы закодированы в метаданных скомпилированной сборки. С другой стороны, делегаты не требуют дополнительных метаданных. Делегат типов делает, но создает эти типы делегатов свободны с точки зрения метаданных.

Но подождите, разве лямбда-выражения / анонимные методы C # не слишком реализованы как скрытые классы?

Да, C # лямбды берут худшее из обоих миров ^^

6 голосов
/ 17 октября 2010

Я просто хотел добавить, что это утверждение из 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...