Una forma que ahora puede hacer esto es tomar ventaja del hecho de que F # llevará a cabo esta conversión automáticamente cuando se invoca métodos en los tipos de .NET que esperan un Expression<Func<...>>
.
No estoy del todo seguro de cuándo se agregó esto al lenguaje, pero sin duda con F # 4, no es necesario convertir explícitamente expresiones F # en LINQ. Si la razón por la que quería hacer esto en primer lugar iba a ser capaz de utilizar las API IQueryable
LINQ (u otras API .NET basada en la expresión), entonces ahora sólo funciona sin ningún esfuerzo, por ejemplo:
someEfDataContext.MyEntities.Single(fun e -> e.Id = 42)
solo trabajos. Aunque parece una lambda ordinaria (no hemos utilizado la sintaxis de expresión de F #), se compila en código que produce un objeto de expresión F # y luego lo pasa a LeafExpressionConverter.QuotationToExpression
para convertirlo en un objeto de expresión LINQ.
Pero a veces querrá apoderarse del objeto de expresión LINQ-style directamente en F #. (Por ejemplo, a veces es útil para escribir una función # F que produce una expresión que se va a utilizar en varias consultas.) En ese caso, se puede escribir un ayudante de la siguiente manera:
type FunAs() =
static member LinqExpression<'T, 'TResult>(e: Expression<Func<'T, 'TResult>>) = e
Esto parece que no hace nada - solo devuelve su argumento. Sin embargo, dado que FunAs
es del tipo .NET, F # compilará automáticamente cualquier sitio de llamada que invoca esto con una expresión fun
en un código que genera una expresión de consulta LINQ adecuada. Ej .:
let linqExpr = FunAs.LinqExpression(fun (e:MyEntity) -> e.Id = 42)
Aquí, linqExpr
será de tipo Expression<Func<MyEntity, bool>>
.
La clave para esto es que este método es miembro de un tipo .NET. Si intenta exactamente lo mismo con una F # función ordinaria:
let funAsLinqExpression<'T, 'TResult>(e: Expression<Func<'T, 'TResult>>) = e
la que parece que debería significar exactamente lo mismo que FunAs.LinqExpression
, encontrará que no se puede llamar de la misma manera. Por ejemplo, si se intenta esto:
let linqExpr = funAsLinqExpression(fun (e:MyEntity) -> e.Id = 42)
Usted obtendrá un error (un poco inútil): 'Esta función toma demasiados argumentos, o se utiliza en un contexto en el que una función no está expected`.
Al hacer que esta función sea miembro de un tipo .NET, podemos aprovechar la ayuda de F # "Parece que está invocando una API de .NET que espera una expresión de estilo LINQ, déjeme ocuparme de eso por usted" característica.
(Es posible que haya alguna manera más explícita de pedir el compilador LINQ para llevar a cabo este mismo truco para usted sin traer un tipo .NET en la imagen, pero no hemos encontrado.)
bueno, lo hizo usted encuentra una manera más simple de hacer esto? – nicolas
en una nota al margen, hay una pregunta relacionada aquí, (aunque no con citas) http://stackoverflow.com/questions/3392000/interop-between-f-and-c-sharp-lambdas – nicolas