Skip to content

Instantly share code, notes, and snippets.

@Allon-Guralnek
Created July 6, 2012 10:33
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 Allon-Guralnek/3059427 to your computer and use it in GitHub Desktop.
Save Allon-Guralnek/3059427 to your computer and use it in GitHub Desktop.
using System;
using System.Diagnostics.Contracts;
using System.Linq.Expressions;
using System.Reflection;
public class DynamicPropertyAccessor<TObject, TProperty>
{
public string Name { get; private set; }
public Type PropertyType { get; private set; }
private Lazy<Func<TObject, TProperty>> Getter { get; set; }
private Lazy<Action<TObject, TProperty>> Setter { get; set; }
public DynamicPropertyAccessor(PropertyInfo targetProperty)
{
Contract.Requires<ArgumentNullException>(targetProperty != null);
Name = targetProperty.Name;
PropertyType = targetProperty.PropertyType;
var objectParam = Expression.Parameter(typeof(TObject), "object");
var specificObject = Expression.Convert(objectParam, targetProperty.ReflectedType);
var property = Expression.Property(specificObject, targetProperty);
if (targetProperty.CanRead)
{
// Getter
var convertToObject = Expression.Convert(property, typeof(TProperty));
var getter = Expression.Lambda<Func<TObject, TProperty>>(convertToObject, objectParam);
Getter = new Lazy<Func<TObject, TProperty>>(getter.Compile);
}
if (targetProperty.CanWrite)
{
// Setter
var valueParam = Expression.Parameter(typeof(TProperty), "value");
var value = Expression.Convert(valueParam, PropertyType);
var assign = Expression.Assign(property, value);
var setter = Expression.Lambda<Action<TObject, TProperty>>(assign, objectParam, valueParam);
Setter = new Lazy<Action<TObject, TProperty>>(setter.Compile);
}
}
public TProperty this[TObject obj]
{
get
{
Contract.Requires(obj != null);
if (Getter == null)
throw new InvalidOperationException(string.Format("The property '{0}', represented by this DynamicPropertyAccessor, is not readable.", Name));
return Getter.Value(obj);
}
set
{
Contract.Requires(obj != null);
if (Setter == null)
throw new InvalidOperationException(string.Format("The property '{0}', represented by this DynamicPropertyAccessor, is not writeable.", Name));
Setter.Value(obj, value);
}
}
}
public class DynamicPropertyAccessor : DynamicPropertyAccessor<object, object>
{
public DynamicPropertyAccessor(PropertyInfo targetProperty) : base(targetProperty) { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment