usar - ¿Cuál es la diferencia entre los delegados en C#y las funciones como valores de primera clase en F#?
tipos de delegates (2)
Más específicamente, cuáles son las características (si las hay) que tienen los delegados que funcionan como valores de primera clase en F # no tienen; y ¿cuáles son las características que funcionan como valores de primera clase (si los hay) que los delegados en C # no tienen?
Los delegados y F # "Valores de función de primera clase" son bastante diferentes.
Los delegados son un mecanismo del CLR, una envoltura segura para el tipo alrededor de pares de función-puntero + objeto (por ejemplo, los métodos, this
puntero se capturan junto con la dirección del método).
Por otro lado, los valores de la función F # son la implementación de una clase abstracta FSharpFunc<,>
(solía llamarse FastFunc<,>
antes de la publicación oficial de F #). La invocación ocurre a través de métodos virtuales ordinarios, que es mucho más rápido que la invocación delegada. Esa es la razón por la que el equipo de F # no usó delegados en primer lugar.
Entonces, si puede "implementar" funciones como valores de primera clase a través de clases abstractas / métodos virtuales, ¿por qué Microsoft agregó delegados?
- No había ninguna alternativa En .NET 1.0 / 1.1, no había genéricos, por lo que tenía que definir un nuevo tipo de delegado (= "tipo de función") para cada firma de función que quisiera usar.
- (No, solo usar interfaces como en Java no cuenta .--P)
Ok, pero tenemos Genéricos desde .NET 2.0, ¿por qué todavía tenemos delegados? ¿Por qué no podemos usar Func<,>
y Action<>
para todo?
- Compatibilidad al revés
- Delegados de multidifusión Los delegados se pueden encadenar para formar nuevos delegados. Este mecanismo se utiliza para implementar eventos en VB.NET y C #. Detrás de escena, un evento es en realidad un solo campo de delegado. Usando la sintaxis
+=
usted esencialmente agrega su evento-delegado-delegado a la cadena de delegados en el campo de evento.
Aparte de los eventos, ¿hay alguna razón para usar delegados sobre FSharpFunc<,>
Sí, una: cada una de las implementaciones de FSharpFunc<,>
, que incluye lambda-expressions *, es una nueva clase. Y en .NET las clases están codificadas en los metadatos del ensamblaje compilado. Los delegados, por otro lado, no requieren metadatos adicionales. Los tipos de delegados hacen, pero la instanciación de estos tipos de delegados es gratuita en términos de metadatos.
Pero espere, ¿no se implementan los métodos C # lambda-expressions / anonymous como clases ocultas?
Sí, las lambdas de C # toman lo peor de ambos mundos ^^
Solo quería agregar que esta declaración de SealedSun no es cierta:
La invocación ocurre a través de métodos virtuales ordinarios, que es mucho más rápido que la invocación delegada. Esa es la razón por la que el equipo de F # no usó delegados en primer lugar.
Las funciones de F # no son más rápidas que la invocación delegada, tal vez ese fue el caso en .NET 1.0, pero hoy en día la invocación de delegado y la invocación de métodos virtuales están prácticamente a la par.
Además, la invocación de funciones de F # que no pueden ser vinculadas estáticamente por el compilador es muy lenta en comparación con invocar a un delegado.
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 los siguientes resultados en mi computadora
delegate call: 65ms
fsharp func (staticly linked): 4ms
fsharp func (dynamic invoke): 356ms