C # Reflection: the fastest way to update a property value?

Is this the fastest way to update a property using reflection? Suppose a property is always int:

PropertyInfo counterPropertyInfo = GetProperty(); int value = (int)counterPropertyInfo.GetValue(this, null); counterPropertyInfo.SetValue(this, value + 1, null); 
+10
performance reflection c # properties
May 28 '11 at
source share
3 answers

Just make sure you somehow cache PropertyInfo so that you are not repeating the type.GetProperty call. Other than that, it would probably be faster if you created a delegate for the type method that performed the increment, or, as Theoman suggested, make the type implement the interface and use it.

+6
May 28 '11 at 12:39 a.m.
source share
— -

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]; //gets 23 ageAccessor[p] = 45; //sets 45 

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); }; 
+17
Apr 18 '13 at 12:25
source share

You should look at FastMember ( nuget , source code ], it compares very quickly with reflection.

I tested these 3 implementations:

For a benchmark, you need a benchmark function:

 static long Benchmark(Action action, int iterationCount, bool print = true) { GC.Collect(); var sw = new Stopwatch(); action(); // Execute once before sw.Start(); for (var i = 0; i <= iterationCount; i++) { action(); } sw.Stop(); if (print) System.Console.WriteLine("Elapsed: {0}ms", sw.ElapsedMilliseconds); return sw.ElapsedMilliseconds; } 

Fake class:

 public class ClassA { public string PropertyA { get; set; } } 

Some testing methods:

 private static void Set(string propertyName, string value) { var obj = new ClassA(); obj.PropertyA = value; } private static void FastMember(string propertyName, string value) { var obj = new ClassA(); var type = obj.GetType(); var accessors = TypeAccessor.Create(type); accessors[obj, "PropertyA"] = "PropertyValue"; } private static void SetValue(string propertyName, string value) { var obj = new ClassA(); var propertyInfo = obj.GetType().GetProperty(propertyName); propertyInfo.SetValue(obj, value); } private static void SetMethodInvoke(string propertyName, string value) { var obj = new ClassA(); var propertyInfo = obj.GetType().GetProperty(propertyName); propertyInfo.SetMethod.Invoke(obj, new object[] { value }); } 

The script itself:

 var iterationCount = 100000; var propertyName = "PropertyA"; var value = "PropertyValue"; Benchmark(() => Set(propertyName, value), iterationCount); Benchmark(() => FastMember(propertyName, value), iterationCount); Benchmark(() => SetValue(propertyName, value), iterationCount); Benchmark(() => SetMethodInvoke(propertyName, value), iterationCount); 

Results for 100,000 iterations:

Default Installer: 3 ms

FastMember: 36ms

PropertyInfo.SetValue: 109ms

PropertyInfo.SetMethod: 91ms

Now you can choose your own !!!

+7
Dec 10 '15 at 3:11
source share



All Articles