Разбирайте строку в запрос LINQ

Какой метод будет считаться наилучшей практикой для разбора строки LINQ в запросе?

Или, другими словами, какой подход имеет смысл конвертировать:

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

в

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

предполагая, что source относится к IEnumerable<Element> или IQueryable<Element> в локальной области.

Ответ 1

Для этого требуется синтаксический анализ текста и интенсивное использование System.Linq.Expressions. Я сделал несколько игр с этим здесь и здесь. Код во второй статье несколько обновляется от первого, но все еще грубого в пятнах. Я продолжал обходить это случаем и иметь несколько более чистую версию, которую я хотел бы опубликовать, если у вас есть интерес. У меня это довольно близко к поддержке хорошего подмножества ANSI SQL 89.

Ответ 3

Вам понадобится парсер языка С# (по крайней мере, v3.5, возможно, v4.0, в зависимости от того, какие функции языка С# вы хотите поддерживать в LINQ). Вы получите результаты анализатора и подаете его непосредственно в дерево выражений с использованием шаблона посетителя. Я еще не уверен, но я готов поспорить, вам также понадобится какой-то анализ типа, чтобы полностью генерировать узлы Expression.

Я ищу то же, что и вы, но мне это действительно не так плохо, поэтому я не искал и не писал ни одного кода в этих строках.

Я написал что-то, что берет ввод строки пользователя и компилирует его в динамическую сборку, используя класс поставщика Microsoft.CSharp.CSharpCodeProvider. Если вы просто хотите взять строки кода и выполнить результат, это должно вам подойдет.

Вот описание консольного инструмента, который я написал, LinqFilter:

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

Здесь находится исходный репозиторий. LinqFilter/Program.cs демонстрирует, как использовать компилятор для компиляции выражения LINQ:

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

Ответ 5

Начиная с .NET 4.6 вы можете использовать CSharpScript для синтаксического анализа Linq, предполагая, что выражение, которое вы хотите проанализировать, находится в запросе, это сделает следующее:

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) {
//
}

Не забудьте передать свой (Data) источник, с которым хотите работать, с глобальными переменными, чтобы иметь доступ к ним из script.

Ответ 6

В то время как это не дает конкретного примера для ответа на ваш вопрос, я бы подумал, что лучше всего было бы построить дерево выражений из строки.

В этом вопросе я спросил, как фильтровать запрос linq с помощью строки, которая показывает, что вы создаете часть дерева выражений. Однако эта концепция может быть расширена для построения целого дерева выражений, представляющего вашу строку.

См. статью из Microsoft.

Есть, вероятно, и другие хорошие сообщения. Кроме того, я думаю, что что-то вроде RavenDB делает это уже в своей базе кода для определения индексов.