I did some benchmarking here when you know type arguments (no general approach will be much different). CreateDelegate will be the fastest approach for a property if you cannot directly access it. With CreateDelegate you get a direct link to GetGetMethod and GetSetMethod for PropertyInfo , so reflection is not used every time.
public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector) { return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>(); } public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector) { return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>(); } // a generic extension for CreateDelegate public static T CreateDelegate<T>(this MethodInfo method) where T : class { return Delegate.CreateDelegate(typeof(T), method) as T; } public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector) { var body = propertySelector.Body as MemberExpression; if (body == null) throw new MissingMemberException("something went wrong"); return body.Member as PropertyInfo; }
So now you call:
TestClass cwp = new TestClass(); var access = BuildGetAccessor((TestClass t) => t.AnyValue); var result = access(cwp);
Or even better, you can encapsulate the logic in a dedicated class to have get and set methods on it.
Something like:
public class Accessor<S> { public static Accessor<S, T> Create<T>(Expression<Func<S, T>> memberSelector) { return new GetterSetter<T>(memberSelector); } public Accessor<S, T> Get<T>(Expression<Func<S, T>> memberSelector) { return Create(memberSelector); } public Accessor() { } class GetterSetter<T> : Accessor<S, T> { public GetterSetter(Expression<Func<S, T>> memberSelector) : base(memberSelector) { } } } public class Accessor<S, T> : Accessor<S> { Func<S, T> Getter; Action<S, T> Setter; public bool IsReadable { get; private set; } public bool IsWritable { get; private set; } public T this[S instance] { get { if (!IsReadable) throw new ArgumentException("Property get method not found."); return Getter(instance); } set { if (!IsWritable) throw new ArgumentException("Property set method not found."); Setter(instance, value); } } protected Accessor(Expression<Func<S, T>> memberSelector) //access not given to outside world { var prop = memberSelector.GetPropertyInfo(); IsReadable = prop.CanRead; IsWritable = prop.CanWrite; AssignDelegate(IsReadable, ref Getter, prop.GetGetMethod()); AssignDelegate(IsWritable, ref Setter, prop.GetSetMethod()); } void AssignDelegate<K>(bool assignable, ref K assignee, MethodInfo assignor) where K : class { if (assignable) assignee = assignor.CreateDelegate<K>(); } }
In short and simple. You can transfer an instance of this class for each class-property pair that you want to get / set.
Using:
Person p = new Person { Age = 23 }; var ageAccessor = Accessor<Person>(x => x.Age); int age = ageAccessor[p];
Bit poor use of indexers here, you can replace it with special "Get" and "Set" methods, but very intuitive for me :)
To avoid having to specify the type every time, like,
var ageAccessor = Accessor<Person>(x => x.Age); var nameAccessor = Accessor<Person>(x => x.Name); var placeAccessor = Accessor<Person>(x => x.Place);
I made the base class Accessor<> instance, which means you can do
var personAccessor = new Accessor<Person>(); var ageAccessor = personAccessor.Get(x => x.Age); var nameAccessor = personAccessor.Get(x => x.Name); var placeAccessor = personAccessor.Get(x => x.Place);
The presence of the base class Accessor<> means that you can consider them as one type, for example,
var personAccessor = new Accessor<Person>(); var personAccessorArray = new Accessor<Person>[] { personAccessor.Get(x => x.Age), personAccessor.Get(x => x.Name), personAccessor.Get(x => x.Place); };