Skip to content

Instantly share code, notes, and snippets.

@jrgcubano
Created November 16, 2016 11:59
Show Gist options
  • Save jrgcubano/6e4df87913411ee9db0c68efc5fc41a3 to your computer and use it in GitHub Desktop.
Save jrgcubano/6e4df87913411ee9db0c68efc5fc41a3 to your computer and use it in GitHub Desktop.
Compiling Expression Trees (create constructors, setters, getters, etc) C#
// Copyright (c) Philipp Wagner. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Via: http://bytefish.de/blog/expression_trees_csharp/
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressionExample
{
public static class ExpressionUtils
{
public static PropertyInfo GetProperty<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> expression)
{
var member = GetMemberExpression(expression).Member;
var property = member as PropertyInfo;
if (property == null)
{
throw new InvalidOperationException(string.Format("Member with Name '{0}' is not a property.", member.Name));
}
return property;
}
private static MemberExpression GetMemberExpression<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> expression)
{
MemberExpression memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
var body = (UnaryExpression)expression.Body;
memberExpression = body.Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException("Not a member access", "expression");
}
return memberExpression;
}
public static Action<TEntity, TProperty> CreateSetter<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
{
PropertyInfo propertyInfo = ExpressionUtils.GetProperty(property);
ParameterExpression instance = Expression.Parameter(typeof(TEntity), "instance");
ParameterExpression parameter = Expression.Parameter(typeof(TProperty), "param");
var body = Expression.Call(instance, propertyInfo.GetSetMethod(), parameter);
var parameters = new ParameterExpression[] { instance, parameter };
return Expression.Lambda<Action<TEntity, TProperty>>(body, parameters).Compile();
}
public static Func<TEntity, TProperty> CreateGetter<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
{
PropertyInfo propertyInfo = ExpressionUtils.GetProperty(property);
ParameterExpression instance = Expression.Parameter(typeof(TEntity), "instance");
var body = Expression.Call(instance, propertyInfo.GetGetMethod());
var parameters = new ParameterExpression[] { instance };
return Expression.Lambda<Func<TEntity, TProperty>>(body, parameters).Compile();
}
public static Func<TEntity> CreateDefaultConstructor<TEntity>()
{
var body = Expression.New(typeof(TEntity));
var lambda = Expression.Lambda<Func<TEntity>>(body);
return lambda.Compile();
}
}
}
// Copyright (c) Philipp Wagner. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// Via: http://bytefish.de/blog/expression_trees_csharp/
using NUnit.Framework;
namespace ExpressionExample
{
[TestFixture]
public class ExpressionUtilsTest
{
public class SampleClass
{
public int IntegerProperty { get; set; }
public string StringProperty { get; set; }
}
[Test]
public void SetterTest()
{
var setterIntegerProperty = ExpressionUtils.CreateSetter<SampleClass, int>(x => x.IntegerProperty);
var setterStringProperty = ExpressionUtils.CreateSetter<SampleClass, string>(x => x.StringProperty);
SampleClass sampleClassInstance = new SampleClass();
setterIntegerProperty(sampleClassInstance, 1);
setterStringProperty(sampleClassInstance, "2");
Assert.AreEqual(1, sampleClassInstance.IntegerProperty);
Assert.AreEqual("2", sampleClassInstance.StringProperty);
}
[Test]
public void GetterTest()
{
var getterIntegerProperty = ExpressionUtils.CreateGetter<SampleClass, int>(x => x.IntegerProperty);
var getterStringProperty = ExpressionUtils.CreateGetter<SampleClass, string>(x => x.StringProperty);
SampleClass sampleClassInstance = new SampleClass()
{
IntegerProperty = 1,
StringProperty = "2"
};
Assert.AreEqual(1, getterIntegerProperty(sampleClassInstance));
Assert.AreEqual("2", getterStringProperty(sampleClassInstance));
}
[Test]
public void CreateDefaultConstructorTest()
{
var defaultConstructor = ExpressionUtils.CreateDefaultConstructor<SampleClass>();
var setterIntegerProperty = ExpressionUtils.CreateSetter<SampleClass, int>(x => x.IntegerProperty);
var sampleEntity = defaultConstructor();
setterIntegerProperty(sampleEntity, 1);
Assert.AreEqual(1, sampleEntity.IntegerProperty);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment