Skip to content

Instantly share code, notes, and snippets.

@jcansdale
Created September 9, 2016 17:31
Show Gist options
  • Save jcansdale/3d4b860188723ea346621b1c51fd8461 to your computer and use it in GitHub Desktop.
Save jcansdale/3d4b860188723ea346621b1c51fd8461 to your computer and use it in GitHub Desktop.
Helper methods to quickly evaluate simple expressions
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;
}
}
}
@chucklu
Copy link

chucklu commented Sep 23, 2019

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

@jcansdale
Copy link
Author

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