views:

53

answers:

3

Hi,

I'm building/updating an EntityFramework EntityObject on runtime. I want to set the properties of the entity class, property names and values are coming from another source.

So I'm doing this;

    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 of doing this?

Something like;

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

Thanks.

+1  A: 

I'm afraid not. Any use of a dynamic object is baked-in at compile time. Any call which could vary at run-time has to be done using reflection.

thecoop
A: 

possibly not with EntityObject, but if you've had an ExpandoObject than you can do

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

Long answer coming up. Reflection is great in many situations, horrible in some but in almost all cases it's slow.

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

I thought I demonstrate one of them: Using compiled expression trees. Note that the expression building is rather expensive too so that's why it's very important to cache the delegate one builds with it in a dictionary (for instance):

Expression Trees was introduced in .NET35 and is used for many things. Here I use them to build a property setter expression and then compile it into a delegate.

The example demonstrates different timing for the different cases but here are my numbers: Control case (hard coded): 0.02s Reflection: 1.78s Expression Tree: 0.06s

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();
      }

   }
}
FuleSnabel
These are the 4 different ways (that I know) how to set a property without reflection:1. Delegate.Create2. DynamicMethod3. Expression Trees4. CallSite<>.Create
FuleSnabel