views:

297

answers:

3

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?

A: 

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>.

David Morton
+4  A: 

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

Thomas Levesque
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.
Loathian
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 type
Thomas Levesque
D'oh ... type not keyword. Thanks Thomas.
Loathian
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.http://blogs.msdn.com/charlie/archive/2008/01/31/expression-tree-basics.aspx
Loathian
A: 

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.

Joe Pitz
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.
Loathian