2012-04-11 3 views
3

Я попытался использовать expandoobjects в запросах LINQ, чтобы иметь возможность запрашивать свойства, созданные во время выполнения, например заголовки из файла csv. Это все работало нормально, если вводить запрос LINQ непосредственно в коде, как в примере:Использование динамических объектов в кодированном виде Запросы LINQ

// initialize testdata 
List<ExpandoObject> hans = new List<ExpandoObject>(); 
string[] names = {"Apfel", "Birne", "Banane", "Orange"}; 
int[] ids = { 1, 2, 3, 4 }; 
for (int i = 0; i < 4; i++) 
{ 
    dynamic horst = new ExpandoObject(); 
    ((IDictionary<string, object>)horst).Add("Fruit", names[i]); 
    ((IDictionary<string, object>)horst).Add("ID", ids[i]); 
    hans.Add(horst); 
} 

// try some LINQ queries, both are working as intended 
var klaus = from dynamic x in hans where x.ID < 3 select x; 
//var klaus = hans.Where(x => x.ID < 3).Select(x => x); 

Затем я попытался прочитать запрос из командной строки и создать динамический запрос LINQ, используя slighty модифицированную версию evaluant LINQ компилятор.

string expression = System.Console.ReadLine(); 
LinqCompiler lc = new LinqCompiler(expression); 
lc.AddSource<ExpandoObject>("hans", hans); 
IEnumerable<ExpandoObject> klaus = (IEnumerable<ExpandoObject>)lc.Evaluate(); 

Пока, как я не использую WHERE или ORDER BY заявления, все нормально, но если WHERE или ORDER BY включен в запрос, я получаю сообщение об ошибке при компиляции кода CodeDOM в linq компилятор: CS1963: Дерево выражений может не содержать динамическую операцию.

Код для запроса создается с помощью следующей строки:

doRequestMethod.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(Query))); 

Я полагаю, что CodeDOM компилятор строит дерево выражения в каком-то иначе, к тому, как прямой напечатанном в LINQ запросе проанализированных , Любая идея получить это для работы будет рассмотрена, в том числе другие идеи для динамического создания запросов для создаваемых во время выполнения объектов.

ответ

2

Чтобы получить ошибку, которую вы получаете, мне пришлось исправить LINQ Compiler, чтобы поддержать dynamic, сообщая ему использовать C# 4.0 и добавить ссылку на Microsoft.CSharp.dll, поэтому я предполагаю, что вы сделали то же самое.

Проблема в источнике в компиляторе LINQ может быть любой коллекцией, включая IQueryable<T>. И если IQueryable<T> должен работать правильно, вам на самом деле нужно обрабатывать его как IQueryable<T>, а не IEnumerable<T>. То, как компилятор LINQ решает это, заключается в том, что он обрабатывает любым источником как IQuerybale<T> с использованием метода расширения AsQueryable().

Это означает, что сгенерированный код выглядит следующим образом:

public object DoRequest(System.Linq.IQueryable<System.Dynamic.ExpandoObject> hans) { 
    return from dynamic x in hans where x.ID < 3 select x; 
} 

Проблема с этим кодом является то, что пытается использовать IQuerybale<T> версии методов LINQ, которые используют Expression с. И, как сообщает сообщение об ошибке, Expression s не поддерживает dynamic.

Я думаю, что самый простой способ исправить это изменить LINQ компилятор использовать IEnumerable<T>, вместо IQuerybale<T> путем изменения AddSource() в:

public void AddSource<T>(string name, IEnumerable<T> source) 
{ 
    this.sources.Add(new SourceDescription(name, typeof(IEnumerable<T>), source)); 
} 

Конечно, это означает, что он не будет хорошо работать для базы данных запросов, но вы не можете делать запросы к базе данных с dynamic в любом случае.

+0

Спасибо, это заставило его работать и при изменении вызова метода DoRequest. Он основан на списке List и вызывает toQueryabale() в вашем источнике. 'Список list = new Список (); foreach (источник источника источника в этих источниках) { list.Add (source.Instance); } ' –

+0

Отличный ответ, решена моя проблема. Благодаря! –