Qual è la differenza tra i delegati in C # e le funzioni come valori di prima classe in F #?
-
29-09-2019 - |
Domanda
In particolare quali sono le caratteristiche (se presenti) che i delegati hanno che le funzioni come valori di prima classe in F # non hanno; e quali sono le caratteristiche che funzioni come valori di prima classe hanno (se presente) che i delegati in C # non hanno?
Soluzione
I delegati e F # "valori della funzione di prima classe" sono molto diverse.
I delegati sono un meccanismo del CLR, un tipo-safe involucro intorno coppie + oggetto funzione-puntatore (per metodi di istanza, il this
puntatore viene catturato insieme all'indirizzo metodo).
I valori # funzione f d'altra parte, sono l'attuazione di una classe astratta FSharpFunc<,>
(ha usato per essere chiamato FastFunc<,>
prima del rilascio ufficiale di F #). Invocazione avviene tramite metodi virtuali ordinari, che è molto più veloce di delegato invocazione.
Questa è la ragione della F # -Team non ha utilizzato i delegati, in primo luogo.
Quindi, se si può "implementare" funziona come valori di prima classe attraverso le classi astratte / metodi virtuali, perché i delegati aggiungere Microsoft?
- Non c'erano alternative in .NET 1.0 / 1.1, non c'erano farmaci generici, quindi si doveva definire un nuovo tipo delegato (= "tipo di funzione") per ogni firma della funzione che si voleva utilizzare .
- (No, solo utilizzando interfacce come in Java non conta. :-P)
Ok, ma abbiamo Generics dal .NET 2.0, perché abbiamo ancora delegati? Perché non possiamo semplicemente usare Func<,>
e Action<>
per tutto?
- Compatibilità
- multicast delegati I delegati possono essere concatenati insieme per formare nuovi delegati. Questo meccanismo viene utilizzato per implementare gli eventi in VB.NET e C #. Dietro le quinte, un evento è in realtà solo un singolo campo delegato. Utilizzando il
+=
sintassi essenzialmente aggiungere il gestore di eventi-delegato alla catena dei delegati del settore eventi.
A parte gli eventi, c'è una ragione per usare delegati nel corso FSharpFunc<,>
Sì, uno: Ogni implementazione di FSharpFunc<,>
, che include lambda-espressioni *, è una nuova classe. E in NET classi sono codificati nei metadati della compilato assemblaggio. I delegati d'altra parte non richiedono metadati aggiuntivi. Il delegato tipo fare, ma creare un'istanza di questi tipi delegato è libera in termini di metadati.
Ma aspettate, non sono C # lambda-espressioni / i metodi anonimi anche implementati come classi nascoste?
Si, C # lambda prendere il peggio dei due mondi ^^
Altri suggerimenti
Volevo solo aggiungere che questa dichiarazione di SealedSun non è vero:
Invocazione avviene via ordinaria metodi virtuali, che è molto più veloce di delegato invocazione. Questo è il motivo il F # -Team non ha utilizzato i delegati, in primo luogo.
F # funzioni non sono più veloci quindi delegano invocazione, forse era il caso di nuovo in .NET 1.0, ma ora un'invocazione giorni delegato e metodi virtuali invocando sono più o meno in pari.
invocando anche F funzioni # che non può essere vincolata staticamente dal compilatore è molto lento rispetto ad invocare un delegato.
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
produce i seguenti risultati sul mio computer
delegate call: 65ms
fsharp func (staticly linked): 4ms
fsharp func (dynamic invoke): 356ms