Using Lambda Expressions trees with IEnumerable
Asked Answered
D

4

11

I've been trying to learn more about using Lamba expression trees and so I created a simple example. Here is the code, this works in LINQPad if pasted in as a C# program.

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; }
}

This results in the following error:

The type arguments for method 'System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

However if I just substitute the first line in main with this:

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

It works fine. Can tell me what I'm doing wrong, please?

Dragone answered 7/3, 2010 at 20:41 Comment(0)
C
8

The Enumerable.Where method takes a Func<T, bool>, not an Expression<Func<T, bool>>. Perhaps you're confusing with Queryable.Where, which does take an expression as a parameter... In your case you don't need an expression, you just need a delegate that can be executed against each item in the sequence. The purpose of expressions is (mostly) to be analysed and translated to something else (SQL for instance), to perform the query against an external data source

Counsellor answered 7/3, 2010 at 20:44 Comment(4)
Yes, that is exactly what I've done wrong. I think I still need to do more reading on this subject to try and understand it better. My other example was using IQueryable and this was working fine, when I built a new example using an IEnumerable list it would not work. I'm not sure what the Expression keyword is intended to signify.Dragone
The fact that lambda expressions are considered as a delegate or an expression tree depends on the context. In your code, you declare the return type as Expression, and this tells the compiler to consider the lambda expression as an expression tree, rather than an executable delegate. BTW, Expression is not a keyword, it's a typeCounsellor
D'oh ... type not keyword. Thanks Thomas.Dragone
I found this article in another stackoverflow post explaining expression trees in more detail. Now I understand the fundamental difference between what I was doing and just using Func I'll delve into expression trees in more detail. blogs.msdn.com/charlie/archive/2008/01/31/…Dragone
M
2

Change the return type of NameContains from Expression<Func<User, Bool>> to simply Func<User, Bool>. In this situation, there's no need to return the Expression, you actually want to return the compiled delegate. There's a difference between the expression that makes up the lambda, and the lambda (which is a delegate) itself.

If you send a lambda into a method, the method can accept the lambda either as an expression, or as a compiled delegate type, depending on what you specify in the parameters. If the incoming parameter type is an Expression, you can send in something that looks like a delegate, however, if the method is expecting a delegate, you have to give it a compiled delegate, not simply an expression. That being said, you can also do something like:

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

Which would compile the expression, and return a Func<User, Bool>.

Mesognathous answered 7/3, 2010 at 20:42 Comment(0)
A
0

Lambda expressions can be treated as either code (delegates) or as data (expression trees)

In your example your are attempting to treat the lambda expression as code.

You would use the Expression<> declaration when you want to treat the lambda expression as data.

Why would you want to do this?

Here is a quote from the Book Linq In Action,

" Expression trees can be given to tools at runtime, which use them to guide their execution or translate them into something else, such as SQL in the case of LINQ to SQL."

Using Expression Trees allows you to take the lambda expression and convert it to data, this is how Linq to SQL works, it takes the lambda expression or query operators or query expressions and converts them to SQL. You of course can view and modify the created expression tree once converted to sql.

Archaism answered 7/3, 2010 at 21:3 Comment(1)
Ok, that helps me understand this quite a bit better. I can see why my other example dealing with LINQ to SQL and an IQueryable return from a table would work with the reurn type Expression now.Dragone
E
0

There is a huge difference between Expression and Func<...>, the Func is a pure delegate you can invoke it directly, the expression is a data structure holds information about an expression like information about lambda expression or Linq Syntax (e.g. From x in list where x.Id = 1 select x). The expression cannot be invoked directly it must be compiled first, Expressions is used to convert the expression from a way to another like Link To Sql which converts an expression to Sql statements, the best way to do this to change the return type of the NameContains Method to Func insted of expression cuz you are working with Linq To Objects, but when using with Linq To Sql you can use both Expression or func.

Episcopalian answered 11/2, 2011 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.