views:

162

answers:

2

I have a linq to objects query in a recursive loop and afraid when the objects approach more then 1000 and a have more then 100 users on the site -- my website will break. so is it possible to compile a linq to objects query.

The linq query does nothing more then find the direct children of a node.

A: 

As with all optimizations, worry about it when you get there. With very high likely-hood, if you ever get 100+ users connected at the same time, your bottleneck will be in someplace completely different.

BlueRaja - Danny Pflughoeft
@BlueRaja: (response to the comment on the deleted post): Yes, but deferred execution has nothing to do with compilation.
Mehrdad Afshari
+8  A: 

To see why the concept of compilation doesn't really make sense for LINQ to Object queries, it's useful to understand how LINQ is implemented. First, it should be clear that LINQ queries written in fluent syntax are converted to the equivalent method call syntax at compile time by the C# compiler regardless of the variant of LINQ you're using:

from person in people
where person.Age < 18
select person.Name
// will be converted to:
people.Where(person => person.Age < 18).Select(person => person.Name)

From now on, the LINQ query is basically a set of method calls taking some arguments and usually transforming an IEnumerable<T> object to another IEnumerable<T> object. Deferred execution, which is a different from compilation, is simply achieved by not taking any object from the original IEnumerable<T> until you're traversing the output IEnumerable<T>. Basically, methods with deferred execution are operating on their arguments symbolically without touching the original collection, building up a generator that queries stuff as you like.

With that in mind, take a look at the lambda expression person => person.Age < 18 in the above expression. It takes a Person object and returns a bool. Lambda expressions are untyped; they can be treated as expression trees or anonymous methods depending on the context their type is inferred from. In this case, the type is inferred from the parameter type of the Where extension method. This is where the distinction of LINQ to SQL and LINQ to Object comes up. In LINQ to Objects, the Where method simply takes Func<Person, bool> as opposed to Expression<Func<Person, bool>>. This essentially means that in LINQ to Objects, the C# compiler compiles the lambda expression down to an anonymous method and generates the IL at compile time and passes a delegate to that method to Where.

In other LINQ flavors, like LINQ to SQL, the lambda is not compiled to IL. Instead, the compiler builds up an expression tree object out of the lambda expression and passes the expression tree to LINQ methods. LINQ methods use these expression trees to build up a model for querying stuff. When the query is being run, the object model built to represent the query using the expression trees will be transformed to another thing (depending on the LINQ variant used) like SQL statements in LINQ to SQL in order to get executed on the database. This transformation process is done at runtime and it's what we call compilation of LINQ queries.

To sum up, the question is compile to what? The reason LINQ to Object doesn't need compilation at runtime is that it's not in expression tree format in the first place; it's already IL.

You almost never need to worry about the performance of LINQ to Objects in comparison to normal looping.

Mehrdad Afshari
Great post. Minor nit: "Lambda expressions are untyped" isn't something I'd like to hear people going around saying. Would "The type of the Lambda expression is determined by the compiler, not declared by the programmer" be better?
David B
@David B: I think it's the correct statement as far as the C# type system goes. A lambda expression never has a type by itself without context (e.g. the statement `var x = i => i;` is invalid even if you explicitly declare the type of `i`: `var x = (int i) => i;`). In this sense it's similar to a *method group*. C# 3.0 spec in §6.5 clearly says: "An anonymous-method-expression or lambda-expression is classified as an anonymous function (§7.14). **The expression does not have a type** but can be implicitly converted to a compatible delegate type or expression tree type." *[emphasis mine]*
Mehrdad Afshari
The language used in the spec is interesting to me. "conversion" should imply some type to start converting from, should it not? Wouldn't it be more appropriate to consider the Lambda expression as having an ExpressionTree type by default, that the compiler implicitly converts to a delegate in certain cases? (Edit: I guess not based on your var example)
David B
@David B: No, it's not the way it works. Things like lambdas and method groups fall outside of the C# type system. Lambdas are converted *from* a "lambda expression" pseudo-type (which is not observable in the type system) to the type inferred from the context. This conversion is not like casting or anything like that. It affects the interpretation of the thing in the compiler directly. This is different from implicit conversions between types.
Mehrdad Afshari
Wow..that was awesome. thanks
Luke101