2012-02-21 19 views
31

Tengo un Func<TCollection, T> en mi código. Lo uso para seleccionar ciertas propiedades.Crear expresión desde Func

En una llamada a otro método necesito Expression<Func<TCollection, T>> como parámetro.

¿Hay alguna manera de convertir (o crear desde) Func<TCollection, T> al Expression<Func<TCollection, T>>?

Gracias

Respuesta

30

No se puede volver a crear una expresión basado en un método ya una expresión necesita conocer las declaraciones originales, no de IL. Sin embargo, puede crear un Expresson que hace una llamada de método a su func como:

Func<int> func =() => 1; 
Expression<Func<int>> expression = Expression.Lambda<Func<int>>(Expression.Call(func.Method)); 

Nota sin embargo, que los sistemas como EF realmente no pueden trabajar con este

+2

Suponiendo que * podría * obtener la IL, sin embargo, podría descompilar la IL, como hacen Reflector e ILSpy. (Por supuesto, no hay garantía de que esto sea exactamente igual al código del cual se compiló el IL.) ¿Hay alguna manera de llegar a la IL de un delegado? – phoog

+5

Creo que es posible que necesite agregar el func.Target en su llamada. Intenté esto con un Func <> más complejo y se quejó de que estaba tratando de llamar a un método de instancia con un objeto nulo. Lo cambié a Expression.Call (Expression.Constant (func.Target), func.Method, args) y todo estaba bien – ben

25

Mientras que usted podría acaba de crear un árbol de expresión que llama a su delegado, es poco probable que sea útil, porque el delegado básicamente será una caja negra en lo que respecta al código que analiza el árbol de expresiones. Suponiendo que está tratando de usar algo como LINQ to SQL, el analizador de consultas tendrá que poder analizar su lógica para convertirla a SQL, y no puede hacerlo si llega a un delegado simple.

Probablemente debería cambiar el código que aparece con el delegado en primer lugar, para crear un árbol de expresiones en su lugar.

7

se puede hacer algo como esto:

Func<object, string> func = a => a.ToString(); 
Expression<Func<object, string>> expr = a => func(a); 

Pero no harán más que una expresión que contiene la llamada al método original de Func. No podrá analizar el contenido del func mismo.

+4

Pero, naturalmente, el Sr. Skeet lo dice mucho mejor que yo. :-) – Simon

9

No puede crear una expresión de un delegado (desde Func<TCollection, T> hasta Expression<Func<TCollection, T>>) pero puede hacer lo opuesto.

Es decir, convertir un Expression<Func<TCollection, T>> en un Func<TCollection, T> compilándolo (.compile).

Por lo tanto, si necesita las dos, puede usar expresiones en sus funciones y, en caso de que las necesite, compilarlas y ejecutarlas en un objeto de colección proporcionado.

Por supuesto que tenemos que tener en cuenta que la compilación de una expresión es lenta.

+0

Gracias, me salvó; ( – Akbari

+0

Esto es exactamente lo que necesitaba. Solo estaba tratando de reducir el código duplicado. Parece que lo estaba mirando por el camino equivocado –

Cuestiones relacionadas