How to dynamically set a class property without using reflection (with dynamic) in C # 4, when the property name comes from another source

I create / update EntityFramework EntityObject at runtime. I want to set the properties of an entity class, the names and values โ€‹โ€‹of the properties come from another source.

So, I do it;

public static EntityCollection<T> UpdateLocaleEntity<T>(EntityCollection<T> entityCollectionToUpdate, params ILocaleControl[] values) where T : EntityObject { foreach (var x in entityCollectionToUpdate) { Type t = typeof(T); dynamic localeEntity = x; string cultureCode = localeEntity.CultureCode; for (int j = 0; j < values.Length; j++) { var value = values[j].GetLocaleValue(cultureCode); t.GetProperty(values[j].EntityPropertyName).SetValue(localeEntity, value, null); } } return entityCollectionToUpdate; } 

So how can I get rid of "t.GetProperty (values โ€‹โ€‹[j] .EntityPropertyName) .SetValue (localeEntity, value, null);" part, is there a dynamic way to do this?

Something like:

dynamicCastedLocaleEntity.GetProperty (values โ€‹โ€‹[j] .EntityPropertyName) = value;

Thanks.

+6
reflection dynamic entity-framework-4
source share
5 answers

I'm afraid not. Any use of the dynamic object is baked at compile time. Any call that may change at run time must be made using reflection.

+1
source share

Long answer. Reflection is wonderful in many situations, terrible in some, but in almost all cases it is slow.

There are at least 4 different ways to set a property in .NET without the need to use reflection.

It seemed to me that I was demonstrating one of them: Using compiled expression trees. Note that constructing an expression is quite expensive, so it is very important to cache the delegate that it builds with it in the dictionary (for example):

Expression trees were introduced in .NET35 and are used for many things. Here I use them to create a setterter expression and then compile it into a delegate.

The example shows different terms for different cases, but here are my numbers: Check register (hard-coded): 0.02 s Reflection: 1.78 Expression tree: 0.06 s

 using System; using System.Linq.Expressions; namespace DifferentPropertSetterStrategies { class TestClass { public string XY { get; set; } } class DelegateFactory { public static Action<object, object> GenerateSetPropertyActionForControl( ) { return (inst, val) => ((TestClass) inst).XY = (string) val; } public static Action<object, object> GenerateSetPropertyActionWithReflection( Type type, string property ) { var propertyInfo = type.GetProperty(property); return (inst, val) => propertyInfo.SetValue (inst, val, null); } public static Action<object,object> GenerateSetPropertyActionWithLinqExpression ( Type type, string property ) { var propertyInfo = type.GetProperty(property); var propertyType = propertyInfo.PropertyType; var instanceParameter = Expression.Parameter(typeof(object), "instance"); var valueParameter = Expression.Parameter(typeof(object), "value"); var lambda = Expression.Lambda<Action<object, object>> ( Expression.Assign ( Expression.Property (Expression.Convert (instanceParameter, type), propertyInfo), Expression.Convert(valueParameter, propertyType)), instanceParameter, valueParameter ); return lambda.Compile(); } } static class Program { static void Time ( string tag, object instance, object value, Action<object, object > action ) { // Cold run action(instance, value); var then = DateTime.Now; const int Count = 2000000; for (var iter = 0; iter < Count; ++iter) { action (instance, value); } var diff = DateTime.Now - then; Console.WriteLine ("{0} {1} times - {2:0.00}s", tag, Count, diff.TotalSeconds); } static void Main(string[] args) { var instance = new TestClass (); var instanceType = instance.GetType (); const string TestProperty = "XY"; const string TestValue = "Test"; // Control case which just uses a hard coded delegate Time( "Control", instance, TestValue, DelegateFactory.GenerateSetPropertyActionForControl () ); Time( "Reflection", instance, TestValue, DelegateFactory.GenerateSetPropertyActionWithReflection (instanceType, TestProperty) ); Time( "Expression Trees", instance, TestValue, DelegateFactory.GenerateSetPropertyActionWithLinqExpression(instanceType, TestProperty) ); Console.ReadKey(); } } } 
+13
source share

maybe not with EntityObject, but if you have an ExpandoObject than you can do

 dynamic entity = new ExpandoObject(); (entity as IDictionary<String, Object>)[values[j].EntityPropertyName] = value 
+2
source share

The open source framework ImpromptuInterface has methods for invoking a row-based call using DLR instead of reflection and is faster than reflection.

 Impromptu.InvokeSet(localeEntity, values[j].EntityPropertyName,value); 
+2
source share

For FuleSnabel's answer, you can speed it up a lot (sometimes twice as fast in my tests). In some tests, it was as fast as the Control solution:

 public static Action<Object,Object> GenerateSetPropertyActionWithLinqExpression2(Type type, String property) { PropertyInfo pi = type.GetProperty(property,BindingFlags.Instance|BindingFlags.Public); MethodInfo mi = pi.GetSetMethod(); Type propertyType = pi.PropertyType; var instance = Expression.Parameter(typeof(Object), "instance"); var value = Expression.Parameter(typeof(Object), "value"); var instance2 = Expression.Convert(instance, type); var value2 = Expression.Convert(value, pi.PropertyType); var callExpr = Expression.Call(instance2, mi, value2); return Expression.Lambda<Action<Object,Object>>(callExpr, instance, value).Compile(); } 
+1
source share

All Articles