Получение значений из ExpressionTrees - PullRequest
6 голосов
/ 11 августа 2010

пусть будет:

Expression<Func<Customer, bool>> expression = c => c.Name == "John";

теперь я получаю значение с помощью:

string myvalue = ((ConstantExpression) bin.Right).Value;

теперь пусть будет:

string x = "John";
Expression<Func<Customer, bool>> expression = c => c.Name == x;

теперь я понимаючто

string myvalue = ((ConstantExpression) bin.Right).Value;

вызовет ошибку, потому что bin.right здесь не является постоянным выражением, это выражение поля, но вопрос в том, как мне получить значение (Джон) из этого?

1 Ответ

13 голосов
/ 11 августа 2010

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

string myvalue = Expression.Lambda<Func<string>>(bin.Right).Compile().Invoke();

Обратите внимание, что это не сработает, если параметр c используется в правой части выражения, поскольку он не будет определен. Также обратите внимание, что это даст вам текущее значение с правой стороны при вызове Invoke, и последующие вызовы могут возвращать разные значения, если поле в объекте изменяется.


Обновление: если вы не знаете тип правой части во время компиляции, вы можете использовать объект, но это сломается для типов значений, таких как int. Вам нужно будет использовать Expression.Convert для принудительной упаковки типов значений перед их возвратом. Это будет работать как для типов значений, так и для ссылочных типов:

object myvalue = Expression.Lambda<Func<object>>(
    Expression.Convert(bin.Right, typeof(object))).Compile().Invoke();

Вы также можете использовать нетипизированную лямбду и DynamicInvoke:

object myvalue = Expression.Lambda(bin.Right).Compile().DynamicInvoke();
...