2010-03-07 12 views
8

He estado tratando de aprender más sobre el uso de árboles de expresión de Lamba, así que creé un ejemplo simple. Aquí está el código, esto funciona en LINQPad si está pegado como un programa C#.Usando árboles Lambda Expressions con IEnumerable

void Main() 
{ 
    IEnumerable<User> list = GetUsers().Where(NameContains("a")); 
    list.Dump("Users"); 
} 

// Methods 
public IEnumerable<User> GetUsers() 
{ 
    yield return new User{Name = "andrew"}; 
    yield return new User{Name = "rob"}; 
    yield return new User{Name = "chris"}; 
    yield return new User{Name = "ryan"}; 
} 

public Expression<Func<User, bool>> NameContains(string namePart) 
{ 
    return u => u.Name.Contains(namePart); 
} 

// Classes 
public class User 
{ 
    public string Name { get; set; } 
} 

Esto da como resultado el siguiente error:

Los argumentos de tipo para el método de 'System.Linq.Enumerable.Where (System.Collections.Generic.IEnumerable, System.Func)' no puede deducirse del uso. Intente especificar los argumentos de tipo explícitamente.

Sin embargo si simplemente sustituya la primera línea principal con este:

IEnumerable<User> list = GetUsers().Where(u => u.Name.Contains("a")); 

Trabaja muy bien. Me puede decir lo que estoy haciendo mal, por favor?

Respuesta

5

El método Enumerable.Where toma un Func<T, bool>, no un Expression<Func<T, bool>>. Tal vez esté confundiendo con Queryable.Where, que toma una expresión como parámetro ... En su caso no necesita una expresión, solo necesita un delegado que pueda ejecutarse contra cada elemento de la secuencia. El propósito de las expresiones es (principalmente) analizar y traducir a otra cosa (SQL por ejemplo) para realizar la consulta en una fuente de datos externa

+0

Sí, eso es exactamente lo que hice mal. Creo que todavía necesito leer más sobre este tema para tratar de entenderlo mejor. Mi otro ejemplo estaba usando IQueryable y esto estaba funcionando bien, cuando construí un nuevo ejemplo usando una lista IEnumerable, no funcionaría. No estoy seguro de qué significa la palabra clave Expression. – Loathian

+0

El hecho de que las expresiones lambda se consideren como un delegado o un árbol de expresiones depende del contexto. En su código, declara el tipo de devolución como Expresión, y esto le dice al compilador que considere la expresión lambda como un árbol de expresiones, en lugar de un delegado ejecutable. Por cierto, Expression no es una palabra clave, es un tipo –

+0

D'oh ... escribe no palabra clave. Gracias Thomas. – Loathian

1

Cambie el tipo de devolución de NameContains de Expression<Func<User, Bool>> a simplemente Func<User, Bool>. En esta situación, no es necesario devolver la expresión, en realidad desea devolver el delegado compilado. Hay una diferencia entre la expresión que compone la lambda y la lambda (que es un delegado).

Si envía un lambda a un método, el método puede aceptar el lambda como una expresión, o como un tipo de delegado compilado, dependiendo de lo que especifique en los parámetros. Si el tipo de parámetro entrante es una Expresión, puede enviar algo que se parece a un delegado, sin embargo, si el método espera un delegado, debe darle un delegado compilado, no simplemente una expresión. Dicho esto, también se puede hacer algo como:

var certainUsers = GetUsers().Where(NameContains("a").Compile()); 

que compile la expresión, y devolver una Func<User, Bool>.

0

Las expresiones Lambda se pueden tratar como código (delegados) o como datos (árboles de expresión)

En su ejemplo, intenta tratar la expresión lambda como código.

Utilizaría la declaración Expression <> cuando desee tratar la expresión lambda como datos.

¿Por qué querrías hacer esto?

Aquí es una cita de la LINQ libro En Acción,

"árboles de expresión se puede dar a las herramientas en tiempo de ejecución, que los utilizan para guiar su ejecución o se traducen en otra cosa, como SQL en el caso de LINQ to SQL."

Usar Expression Trees le permite tomar la expresión lambda y convertirla en datos, así es como funciona Linq to SQL, toma la expresión lambda o consulta los operadores o las expresiones de consulta y los convierte a SQL. Usted puede, por supuesto, ver y modificar el árbol de expresiones creado una vez convertido a sql.

+0

Ok, eso me ayuda a entender esto un poco mejor. Puedo ver por qué mi otro ejemplo relacionado con LINQ to SQL y un retorno IQueryable de una tabla funcionaría ahora con la expresión de tipo de renovación. – Loathian

0

Hay una gran diferencia entre Expression y Func < ...>, el Func es un delegado puro, puede invocarlo directamente, la expresión es una estructura de datos que contiene información sobre una expresión como información sobre la expresión lambda o la sintaxis Linq (por ejemplo, de x en la lista donde x.Id = 1 seleccione x). La expresión no puede invocarse directamente, primero debe compilarse, Expresiones se usa para convertir la expresión de una manera a otro l ike Link To Sql que convierte una expresión en sentencias Sql, la mejor manera de hacerlo es cambiar el tipo de retorno del método NameContains a Func insted of expression porque estás trabajando con Linq To Objects, pero cuando lo usas con Linq To Sql puedes usa tanto Expression como func.

Cuestiones relacionadas