Подтвердить что ты не робот

В чем разница между делегатами в С# и функциями как значения первого класса в F #?

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

4b9b3361

Ответ 1

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

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

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

Итак, если вы можете "реализовать" функции как значения первого класса через абстрактные классы/виртуальные методы, почему Microsoft добавила делегатов?

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

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

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

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

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

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

Да, С# lambdas берут худшее из обоих миров ^^

Ответ 2

Я просто хотел добавить, что это утверждение из SealedSun неверно:

Вызов происходит через обычные виртуальные методы, которые намного быстрее чем вызов делегата. Это причина, по которой F # -team не использовал делегатов в первую очередь.

Функции 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