当属性名来自其他源时,如何在C#4中动态设置类的属性而不使用反射(带动态)

Alp*_*tin 6 reflection dynamic entity-framework-4 c#-4.0

我正在运行时构建/更新EntityFramework EntityObject.我想设置实体类的属性,属性名称和值来自另一个源.

所以我这样做;

    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;
    }
Run Code Online (Sandbox Code Playgroud)

那么,我怎样才能摆脱"t.GetProperty(values [j] .EntityPropertyName).SetValue(localeEntity,value,null);" 部分,是否有一种动态的方式来做到这一点?

就像是;

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

Thanks.

Jus*_*mer 13

答案很长.在许多情况下反射是很好的,有些可怕但在几乎所有情况下它都很慢.

至少有4种不同的方法可以在.NET中设置属性而无需使用反射.

我以为我演示了其中一个:使用编译的表达式树.请注意,表达式构建也相当昂贵,这就是为什么在一个字典中缓存委托一个构建非常重要(例如):

Expression Trees是在.NET35中引入的,用于很多事情.在这里,我使用它们来构建属性setter表达式,然后将其编译为委托.

该示例演示了不同情况的不同时间,但这里是我的数字:控制情况(硬编码):0.02s反射:1.78s表达式树: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();
      }

   }
}
Run Code Online (Sandbox Code Playgroud)


the*_*oop 2

恐怕不是。对象的任何使用dynamic都是在编译时内置的。任何在运行时可能发生变化的调用都必须使用反射来完成。