Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I did some <a href="https://stackoverflow.com/questions/10820453/reflection-performance-create-delegate-properties-c">benchmarking here</a> when you know the type arguments (a non generic approach wont be very different). <code>CreateDelegate</code> would be the fastest approach for a property if you can't directly access it. With <code>CreateDelegate</code> you get a direct handle to <code>GetGetMethod</code> and <code>GetSetMethod</code> of the <code>PropertyInfo</code>, hence reflection is not used every time.</p> <pre><code>public static Func&lt;S, T&gt; BuildGetAccessor&lt;S, T&gt;(Expression&lt;Func&lt;S, T&gt;&gt; propertySelector) { return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate&lt;Func&lt;S, T&gt;&gt;(); } public static Action&lt;S, T&gt; BuildSetAccessor&lt;S, T&gt;(Expression&lt;Func&lt;S, T&gt;&gt; propertySelector) { return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate&lt;Action&lt;S, T&gt;&gt;(); } // a generic extension for CreateDelegate public static T CreateDelegate&lt;T&gt;(this MethodInfo method) where T : class { return Delegate.CreateDelegate(typeof(T), method) as T; } public static PropertyInfo GetPropertyInfo&lt;S, T&gt;(this Expression&lt;Func&lt;S, T&gt;&gt; propertySelector) { var body = propertySelector.Body as MemberExpression; if (body == null) throw new MissingMemberException("something went wrong"); return body.Member as PropertyInfo; } </code></pre> <p>So now you call:</p> <pre><code>TestClass cwp = new TestClass(); var access = BuildGetAccessor((TestClass t) =&gt; t.AnyValue); var result = access(cwp); </code></pre> <p>Or even better you can encapsulate the logic in a dedicated class to have a get and set methods on it.</p> <p>Something like:</p> <pre><code>public class Accessor&lt;S&gt; { public static Accessor&lt;S, T&gt; Create&lt;T&gt;(Expression&lt;Func&lt;S, T&gt;&gt; memberSelector) { return new GetterSetter&lt;T&gt;(memberSelector); } public Accessor&lt;S, T&gt; Get&lt;T&gt;(Expression&lt;Func&lt;S, T&gt;&gt; memberSelector) { return Create(memberSelector); } public Accessor() { } class GetterSetter&lt;T&gt; : Accessor&lt;S, T&gt; { public GetterSetter(Expression&lt;Func&lt;S, T&gt;&gt; memberSelector) : base(memberSelector) { } } } public class Accessor&lt;S, T&gt; : Accessor&lt;S&gt; { Func&lt;S, T&gt; Getter; Action&lt;S, T&gt; 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&lt;Func&lt;S, T&gt;&gt; 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&lt;K&gt;(bool assignable, ref K assignee, MethodInfo assignor) where K : class { if (assignable) assignee = assignor.CreateDelegate&lt;K&gt;(); } } </code></pre> <p>Short and simple. You can carry around an instance of this class for every "class-property" pair you wish to get/set.</p> <p>Usage:</p> <pre><code>Person p = new Person { Age = 23 }; var ageAccessor = Accessor&lt;Person&gt;(x =&gt; x.Age); int age = ageAccessor[p]; //gets 23 ageAccessor[p] = 45; //sets 45 </code></pre> <p>Bit bad use of indexers here, you may replace it with dedicated "Get" and "Set" methods, but very intuitive to me :)</p> <p>To avoid having to specify type each time like,</p> <pre><code>var ageAccessor = Accessor&lt;Person&gt;(x =&gt; x.Age); var nameAccessor = Accessor&lt;Person&gt;(x =&gt; x.Name); var placeAccessor = Accessor&lt;Person&gt;(x =&gt; x.Place); </code></pre> <p>I made the base <code>Accessor&lt;&gt;</code> class instantiable, which means you can do</p> <pre><code>var personAccessor = new Accessor&lt;Person&gt;(); var ageAccessor = personAccessor.Get(x =&gt; x.Age); var nameAccessor = personAccessor.Get(x =&gt; x.Name); var placeAccessor = personAccessor.Get(x =&gt; x.Place); </code></pre> <p>Having a base <code>Accessor&lt;&gt;</code> class means you can treat them as one type, for eg,</p> <pre><code>var personAccessor = new Accessor&lt;Person&gt;(); var personAccessorArray = new Accessor&lt;Person&gt;[] { personAccessor.Get(x =&gt; x.Age), personAccessor.Get(x =&gt; x.Name), personAccessor.Get(x =&gt; x.Place); }; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload