You can use expression tree as a code builder with a higher abstraction level then asembly emit and faster then CodeCompiler. Here is some proof of the concept that i used to convince our team to use them as a replacement for CodeCompiler.
[TestClass]
public class WhenINeedToAccessPropertiesByNameHavingATypeReference
{
public class SomeCategoryData
{
public DateTime CreatedDate { get; set; }
}
[TestMethod]
public void ICanDoThatWithAnExpressionAndItPerformsWell()
{
// INIT
var someCategoryData =
Enumerable.Range(1970, 100).Select(year=>
new SomeCategoryData {CreatedDate = new DateTime(year,1,1)}).Cast<object>();
var t = typeof(SomeCategoryData); // or it can be: t = someCategoryData.First().GetType();
var compiled = Stopwatch.StartNew();
// ACT
var filter = AccessPropertyByNameInCompiledMannerSomehow(t, "CreatedDate");
// ASSERT
Trace.WriteLine(string.Format("compiled in: {0}", compiled.Elapsed));
Assert.IsTrue(compiled.ElapsedMilliseconds < 3, "compiles fast enough");
var executed = Stopwatch.StartNew();
// ACT
List<object> result = null;
for (var i = 0; i < 10000; i++)
{
result = someCategoryData.Where(d => filter(d, new DateTime(2000, 1, 1), new DateTime(2009, 1, 1)))
.ToList();
}
executed.Stop();
Trace.WriteLine(string.Format("executed in: {0}", executed.Elapsed));
// ASSERT
Assert.AreEqual(10, result.Count, "insure compiled code actually works");
Assert.IsTrue(executed.ElapsedMilliseconds < 300, "runs fast enough");
}
private static Func<object, DateTime, DateTime, bool>
AccessPropertyByNameInCompiledMannerSomehow(Type t, string fieldToFilterBy)
{
var objectParameter = Expression.Parameter(typeof(object), "p");
var instance = Expression.Convert(objectParameter, t);
var lower = Expression.Parameter(typeof(DateTime), "l");
var upper = Expression.Parameter(typeof(DateTime), "u");
var composite = Expression.Lambda<Func<object, DateTime, DateTime, bool>>(
Expression.And(
Expression.LessThanOrEqual(
lower,
Expression.PropertyOrField(instance, fieldToFilterBy)
),
Expression.GreaterThanOrEqual(
upper,
Expression.PropertyOrField(instance, fieldToFilterBy)
)
), objectParameter, lower, upper
);
return composite.Compile();
}
}