Skip to content

Instantly share code, notes, and snippets.

@duncansmart
Created April 14, 2011 12:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duncansmart/919337 to your computer and use it in GitHub Desktop.
Save duncansmart/919337 to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Diagnostics;
// Our model classes
class Person
{
public int Id { get; set; }
public FullName FullName { get; set; }
public DateTime StartDate { get; set; }
}
class FullName
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
// Test
class Program
{
static void Main(string[] args)
{
Person model = new Person
{
Id = 123,
StartDate = new DateTime(2002, 7, 1),
FullName = new FullName
{
FirstName = "Duncan",
LastName = "Smart",
}
};
var nameBinder = CompileDataBinder<Person, string>("model.FullName.FirstName");
string fname = nameBinder(model);
Debug.Assert(fname == "Duncan");
// Note how here we pretend we don't know TProp type
var idBinder = CompileDataBinder<Person, object>("model.Id");
object id = idBinder(model);
Debug.Assert(id.Equals(123));
// Here we get it to convert to string
var idStringBinder = CompileDataBinder<Person, string>("model.Id");
string idStr = idStringBinder(model);
Debug.Assert(idStr == "123");
// convert date to string
var dateBinder = CompileDataBinder<Person, string>("model.StartDate");
string dateStr = dateBinder(model);
Debug.Assert(dateStr == new DateTime(2002, 7, 1).ToString());
}
static Func<TModel, TProp> CompileDataBinder<TModel, TProp>(string expression)
{
var propNames = expression.Split('.');
var model = Expression.Parameter(typeof(TModel), "model");
Expression body = model;
foreach (string propName in propNames.Skip(1))
body = Expression.Property(body, propName);
if (body.Type != typeof(TProp))
{
try
{
// Shame there's no TryConvert
body = Expression.Convert(body, typeof(TProp));
}
catch (InvalidOperationException)
{
// No cast, use System.Convert.ToXXX
var convertMethod = typeof(Convert).GetMethod("To" + typeof(TProp).Name, new[] { body.Type });
if (convertMethod == null)
throw new InvalidOperationException(string.Format("Couldn't find conversion from {0} to {1}.", body.Type, typeof(TProp)));
body = Expression.Call(convertMethod, body);
}
}
//Debug.WriteLine(typeof(TProp).Name + " '" + expression + "' = " + body);
var func = Expression.Lambda<Func<TModel, TProp>>(body, model).Compile();
//TODO: cache funcs
return func;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment