2

This is a follow up to a question I asked earlier seen here:

Confused about passing Expression vs. Func arguments

The accepted answerer there suggests refactoring an Expression referencing local objects into something that Linq to Entities can actually execute against the backing store (in my case SQL Server)

I've spent a long time trying to come up with something that will work for what I'm doing. My original

Func<Thing, bool> whereClause

was referencing a local Dictionary object which Linq to Entities or SQL could not understand at runtime. I tried refactoring into multiple lists which faked a dictionary, and Arrays after that. Each time, I got runtime errors complaining about the context doesn't recognize things like the methods on a List, or array indexers.

Eventually I gave up and just provided an additional method which takes a Func argument for when I cannot come up with the proper Expression.

I'm not trying to find a solution to my specific problem, I'm just wondering in general if it is always possible to convert, say a

Func<Thing, bool>

to an equivalent

Expression<Func<Thing, bool>>

which can run against Linq to Entities. Or if there are many examples of querys where you simply must pull the data into memory first.

Community
  • 1
  • 1
Erix
  • 7,059
  • 2
  • 35
  • 61

2 Answers2

7

You don't convert a Func to an expression tree - the compiler converts a lambda expression to an expression tree... and no, that's not always possible. For example, you can't convert a statement lambda to an expression tree:

Expression<Func<string, int>> valid = text => text.Length;

Expression<Func<string, int>> invalid = text => { return text.Length; };

There are various other restrictions, too.

Even when you can create an expression tree (and if you do it manually you can build ones which the C# compiler wouldn't, particularly in .NET 4) that's not the same thing as the expression tree representing something that LINQ to SQL (etc) can translate appropriately.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
5

Jon is of course correct; you turn a lambda into an expression tree.

To expand a bit on his "various other restrictions" handwave: a lambda converted to an expression tree may not contain:

  • statements
  • expressions useful primarily for their state mutations: assignment, compound assignment, increment and decrement operators
  • dynamic operations of any kind
  • multi-dimensional array initializers
  • removed partial methods
  • base access
  • pointer operations of any kind
  • sizeof(T) except for where T is a built-in type
  • COM-style indexed property invocations
  • COM-style "optional ref" invocations
  • C-style variadic method invocations
  • optional-argument and named-argument invocations
  • method groups (except of course when in an invocation)

That's not an exhaustive list; there are some other weird corner cases. But that should cover the majority of them.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thanks Eric. These are only restrictions on what the language itself provides, correct? Meaning You could satisfy all of these conditions but still have Linq to SQL fail to translate it? – Erix Jan 04 '12 at 20:07
  • 1
    @Erix: Correct. I have no idea what the restrictions are for LINQ to SQL. – Eric Lippert Jan 04 '12 at 20:28