Parse string into a LINQ query
Asked Answered
A

6

12

What method would be considered best practice for parsing a LINQ string into a query?

Or in other words, what approach makes the most sense to convert:

 string query = @"from element in source
                  where element.Property = ""param""
                  select element";

into

 IEnumerable<Element> = from element in source 
                        where element.Property = "param"
                        select element;

assuming that source refers to an IEnumerable<Element> or IQueryable<Element> in the local scope.

Auriculate answered 23/3, 2011 at 1:45 Comment(3)
Unfortunately, this is going to be tough. I hope that someone surprises me and proves me wrong, but I don't expect it to happen.Meadors
Doesn't exactly answer your question but pretty close weblogs.asp.net/scottgu/archive/2008/01/07/…Marxist
Sounds like what www.linqpad.net would do... but I don't know HOW they do it.Tabbie
S
7

Starting with .NET 4.6 you can use CSharpScript to parse Linq. Assuming the expression you want to parse is in string variable "query", this will do it:

string query = "from element in source where element.Property = ""param"" select element";
IEnumerable result = null;
try 
{
    var scriptOptions = ScriptOptions.Default.WithReferences(typeof(System.Linq.Enumerable).Assembly).WithImports("System.Linq");
    result = await CSharpScript.EvaluateAsync<IEnumerable>(
             query,
             scriptOptions,
             globals: global);
} catch (CompilationErrorException ex) {
//
}

Don't forget to pass your (Data)source you want to work on, with the global-variable(s) to have access to them in script parsing.

Stubblefield answered 20/7, 2016 at 10:53 Comment(2)
Any way to do this in .NET Core yet?Babby
I doubt it will be that easy. Guess the needed CSharpScript and Linq are not part of .NET Core. Some UpVote would still be nice.Stubblefield
T
5

It requires some text parsing and heavy use of System.Linq.Expressions. I've done some toying with this here and here. The code in the second article is somewhat updated from the first but still rough in spots. I've continued to mess round with this on occasion and have a somewhat cleaner version that I've been meaning to post if you have any interest. I've got it pretty close to supporting a good subset of ANSI SQL 89.

Tyner answered 23/3, 2011 at 2:35 Comment(0)
C
3

You're going to need a C# language parser (at least v3.5, possibly v4.0, depending on what C# language features you wish to support in LINQ). You'll take those parser results and feed it directly into an Expression tree using a visitor pattern. I'm not sure yet but I'm willing to bet you'll also need some form of type analysis to fully generate the Expression nodes.

I'm looking for the same thing as you, but I don't really need it that badly so I haven't searched hard nor written any code along these lines.

I have written something that takes user string input and compiles it to a dynamic assembly using the Microsoft.CSharp.CSharpCodeProvider compiler provider class. If you just want to take strings of code and execute the result, this should suit you fine.

Here's the description of the console tool I wrote, LinqFilter:

http://bittwiddlers.org/?p=141

Here's the source repository. LinqFilter/Program.cs demonstrates how to use the compiler to compile the LINQ expression:

http://bittwiddlers.org/viewsvn/trunk/public/LinqFilter/?root=WellDunne

Comet answered 23/3, 2011 at 2:53 Comment(3)
A thought occurs: if you were paranoid about the string having to be an expression, you could use the CSharpCodeProvider and generate code along the lines of Expression<IQueryable<T>> query = (LINQ CODE HERE); and then you'll have the expression tree built for you by the compiler. It's just a matter of a Compile() call to get back a delegate to execute it and some reflection to find you the dynamic assembly's method that you generated so you can execute that. Hope this makes sense; I'm sort of rambling here lol. :)Comet
Forgive me, it needs to be an Expression<Func<IQueryable<T>>> or Expression<Func<IEnumerable<T>>>. In your generated code, you can safely concatenate as follows: Expression<Func<IQueryable<T>>> getQuery = () => (linq query here); The compiler will only accept valid expressions that can be parsed into an Expression tree. For C# v3.5, this excludes statements and assignment expressions.Comet
To execute the query, take that getQuery and do getQuery.Compile()(). The two parenthesis pairs are not a mistake here. You invoke the Compile() method which gives you back a delegate and you invoke that delegate which returns you back your IQueryable<T> or whatever IQueryable/IEnumerable type you expect back.Comet
C
2

This might work for you: C# eval equivalent?

Certes answered 23/3, 2011 at 1:57 Comment(0)
I
2

This may or may not help you, but check out LINQ Dynamic Query Library.

Immethodical answered 23/3, 2011 at 3:2 Comment(0)
M
0

While this doesn't specifically give an example to answer your question I would have thought the best practice would generally be to build an expression tree from the string.

In this question I asked how to filter a linq query with a string which shows you building a portion of an expression tree. This concept however can be extended to build an entire expression tree representing your string.

See this article from Microsoft.

There are probably other better posts out there as well. Additionally I think something like RavenDB does this already in its code base for defining indexes.

Massorete answered 23/3, 2011 at 2:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.