Created
September 9, 2016 17:31
-
-
Save jcansdale/3d4b860188723ea346621b1c51fd8461 to your computer and use it in GitHub Desktop.
Helper methods to quickly evaluate simple expressions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Reflection; | |
using System.Collections.Generic; | |
using System.Linq.Expressions; | |
public static class ExpressionUtilities | |
{ | |
public static object GetValue(Expression expression) | |
{ | |
return getValue(expression, true); | |
} | |
public static object GetValueWithoutCompiling(Expression expression) | |
{ | |
return getValue(expression, false); | |
} | |
static object getValue(Expression expression, bool allowCompile) | |
{ | |
if (expression == null) | |
{ | |
return null; | |
} | |
if (expression is ConstantExpression) | |
{ | |
var constantExpression = (ConstantExpression)expression; | |
return getValue(constantExpression); | |
} | |
if (expression is MemberExpression) | |
{ | |
var memberExpression = (MemberExpression)expression; | |
return getValue(memberExpression, allowCompile); | |
} | |
if (expression is MethodCallExpression) | |
{ | |
var methodCallExpression = (MethodCallExpression)expression; | |
return getValue(methodCallExpression, allowCompile); | |
} | |
if (allowCompile) | |
{ | |
return GetValueUsingCompile(expression); | |
} | |
throw new Exception("Couldn't evaluate Expression without compiling: " + expression); | |
} | |
static object getValue(ConstantExpression constantExpression) | |
{ | |
return constantExpression.Value; | |
} | |
private static object getValue(MemberExpression memberExpression, bool allowCompile) | |
{ | |
var value = getValue(memberExpression.Expression, allowCompile); | |
var member = memberExpression.Member; | |
if (member is FieldInfo) | |
{ | |
var fieldInfo = (FieldInfo)member; | |
return fieldInfo.GetValue(value); | |
} | |
if (member is PropertyInfo) | |
{ | |
var propertyInfo = (PropertyInfo)member; | |
try | |
{ | |
return propertyInfo.GetValue(value); | |
} | |
catch (TargetInvocationException e) | |
{ | |
throw e.InnerException; | |
} | |
} | |
throw new Exception("Unknown member type: " + member.GetType()); | |
} | |
private static object getValue(MethodCallExpression methodCallExpression, bool allowCompile) | |
{ | |
var paras = getArray(methodCallExpression.Arguments, true); | |
var obj = getValue(methodCallExpression.Object, allowCompile); | |
try | |
{ | |
return methodCallExpression.Method.Invoke(obj, paras); | |
} | |
catch (TargetInvocationException e) | |
{ | |
throw e.InnerException; | |
} | |
} | |
static object[] getArray(IEnumerable<Expression> expressions, bool allowCompile) | |
{ | |
var list = new List<object>(); | |
foreach (var expression in expressions) | |
{ | |
var value = getValue(expression, allowCompile); | |
list.Add(value); | |
} | |
return list.ToArray(); | |
} | |
public static object GetValueUsingCompile(Expression expression) | |
{ | |
var lambdaExpression = Expression.Lambda(expression); | |
var dele = lambdaExpression.Compile(); | |
return dele.DynamicInvoke(); | |
} | |
} | |
namespace Tests | |
{ | |
using NUnit.Framework; | |
using System; | |
using System.Text; | |
using System.Linq.Expressions; | |
public class ExpressionUtilitiesTests | |
{ | |
[Test] | |
public void GetValue_ConstantExpression_ReturnValue() | |
{ | |
var expression = ExpressionBody(() => "__String__"); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_Null_ReturnNull() | |
{ | |
var expression = ExpressionBody(() => (string)null); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_MemberExpression_ReturnProperty() | |
{ | |
var expression = ExpressionBody(() => Encoding.ASCII); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_PropertyExpression_ReturnValue() | |
{ | |
var expression = ExpressionBody(() => InstanceProp); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
string InstanceProp { get; } = "__InstanceProp__"; | |
[Test] | |
public void GetValue_StaticProperty_ReturnValue() | |
{ | |
var expression = ExpressionBody(() => StaticProperty); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
static string StaticProperty { get; } = "__StaticProperty__"; | |
[Test] | |
public void GetValue_MethodCallWithArguments_ReturnValue() | |
{ | |
var expression = ExpressionBody(() => string.Format("{0} {1} {2}", "foo", "bar", 1)); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_MethodExpression_ReturnValue() | |
{ | |
var expression = ExpressionBody(() => 666.ToString()); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_RecursiveMethodCalls_ReturnValue() | |
{ | |
var expression = ExpressionBody(() => 666.ToString().ToString()); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_Local_ReturnLocal() | |
{ | |
var local = "__Local__"; | |
var expression = ExpressionBody(() => local); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValueWithoutCompiling(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
} | |
[Test] | |
public void GetValue_Add_GetValueWithoutCompilingThrowsException() | |
{ | |
var x = 42; | |
var expression = ExpressionBody(() => x + 666); | |
var expectedValue = ExpressionUtilities.GetValueUsingCompile(expression); | |
var value = ExpressionUtilities.GetValue(expression); | |
Assert.That(value, Is.EqualTo(expectedValue)); | |
Assert.Throws<Exception>( | |
() => ExpressionUtilities.GetValueWithoutCompiling(expression)); | |
} | |
[Test] | |
public void GetValue_MethodThrowsException_ThrowsException() | |
{ | |
var expression = ExpressionBody(() => methodThrowsException()); | |
Assert.Throws<Exception>( | |
() => ExpressionUtilities.GetValue(expression)); | |
} | |
static int methodThrowsException() | |
{ | |
throw new Exception("Boom!"); | |
} | |
[Test] | |
public void GetValue_PropertyThrowsException_ThrowsException() | |
{ | |
var expression = ExpressionBody(() => PropertyThrowsException); | |
Assert.Throws<Exception>( | |
() => ExpressionUtilities.GetValue(expression)); | |
} | |
static int PropertyThrowsException | |
{ | |
get | |
{ | |
throw new Exception("Boom!"); | |
} | |
} | |
static Expression ExpressionBody<T>(Expression<Func<T>> expression) | |
{ | |
return expression.Body; | |
} | |
} | |
} |
What was the expression you tried to evaluate?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When use ExpressionUtilities.GetValue method, I got
Message:variable 'l' of type 'AdminGenericModel' referenced from scope '', but it is not defined
When use GetValueWithoutCompiling method, I got
System.Exception: Couldn't evaluate Expression without compiling: l