2015-04-11 1 views
3

Я застрял на этом часами. Все, что я хочу сделать, это построить дерево выражений, переписав это выражение с помощью Expression class APIs:Переписать выражение Lambda с помощью API System.Linq.Expressions

var Expression<Func<T, bool>> expr = x => x.SomeProperty == value; 

То, что я получил до сих пор являются:

{ 
    var param = Expression.Parameter(typeof(T), "x"); 
    var lhs = Expression.Property(param, "SomeProperty"); 
    var rhs = Expression.Constant(value, value.GetType()); 
    return Expression.Call(typeof(object).GetMethod("Equals", BindingFlags.Static | BindingFlags.Public), lhs, rhs); 
} 

Это прекрасно работает, если T примитивный тип или перечисление , Но я получил исключение, если T является ссылкой типа, class и т.д.

Сообщение исключения:

Невозможно создать постоянное значение типа «TypeName». В этом контексте поддерживаются только примитивные типы или типы перечисления.

Заранее спасибо.

+1

Из [docs] (https://msdn.microsoft.com/en-us/library/system.linq.expressions.constantexpression (v = vs.110) .aspx) Я бы предположил, что вы не можете создайте 'ConstantExpression' из ничего, кроме константы * компиляции *. Это согласуется с сообщением об ошибке, которое вы получаете, поскольку * примитивные типы и типы перечисления * являются единственными, которые поддерживают * compile time * константы. Откуда берется значение 'value'? –

+0

Вы пытались использовать поиск дерева выражений рефлектора? http://blogs.msmvps.com/paulomorgado/2010/08/05/mastering-expression-trees-with-net-reflector/ – Hylaean

+0

Значение является свойством DataContract. Он десериализуется WCF. Затем я использую десериализованный объект для создания выражения. –

ответ

0

Выражение, сгенерированное, передается на вызов Linq Where. Как это.

Context.Sources.Where(criteria.BuildQuery()); 

Исключение было выбрано, когда выражение оценивается/переводится.

Если я скомпилирую выражение и передаю делегат на вызов Where, все работает так, как ожидалось.

Context.Sources.Where(criteria.BuildQuery().Compile()); 

Я не уверен, какая разница, если кто-то знает, почему, пожалуйста, просветите нас.

1

Вам не нужно указывать тип явно в этом случае, если значение не является нулевым (что я предполагаю, что это не так, поскольку вы вызываете на нем GetType()).

Это должно сделать это.

var param = Expression.Parameter(typeof(T), "x"); 
var property = Expression.Property(param, "SomeProperty"); 
var compareValue = Expression.Constant(value); 
var equals = Expression.Equal(property, compareValue); 
return Expression.Lambda<Func<T, bool>>(equals, param); 
+0

Я начал без явного типа.Но это не сработало. –

+1

Я думаю, вам нужно будет предоставить больше информации о домене. Я только что попробовал это в быстром консольном приложении, и он отлично работает, чтобы создать простое выражение равенства. Какой тип T, когда он выдает исключение? – christophano

+0

Ваше решение хорошее. Я тестировал в быстром консольном приложении и работает так, как ожидалось. Мой реальный код немного сложнее. Позвольте мне немного изменить свой вопрос и посмотреть, где этот разрыв падает. Спасибо. –

Смежные вопросы