Reflection 当属性名来自另一个源时,如何在不使用C#4中的反射(带有dynamic)的情况下动态设置类的属性

Reflection 当属性名来自另一个源时,如何在不使用C#4中的反射(带有dynamic)的情况下动态设置类的属性,reflection,dynamic,c#-4.0,entity-framework-4,Reflection,Dynamic,C# 4.0,Entity Framework 4,我正在运行时上构建/更新EntityFramework EntityObject。我想设置实体类的属性,属性名称和值来自另一个源 所以我正在这样做 public static EntityCollection<T> UpdateLocaleEntity<T>(EntityCollection<T> entityCollectionToUpdate, params ILocaleControl[] values) where T : EntityObje

我正在运行时上构建/更新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;
    }
公共静态EntityCollection UpdateLocaleEntity(EntityCollection entityCollectionToUpdate,参数ILocaleControl[]值),其中T:EntityObject
{
foreach(entityCollectionToUpdate中的变量x)
{
类型t=类型(t);
动态局部收敛性=x;
字符串cultureCode=localeEntity.cultureCode;
对于(int j=0;j
那么,我如何摆脱“t.GetProperty(values[j].EntityPropertyName).SetValue(localeEntity,value,null);”部分,有没有一种动态的方法可以做到这一点

有点像

dynamicCastedLocaleEntity.GetProperty(值[j].EntityPropertyName)=值


谢谢。

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

可能不使用EntityObject,但是如果您有一个ExpandoObject,那么您就无法使用它了

dynamic entity = new ExpandoObject();
(entity as IDictionary<String, Object>)[values[j].EntityPropertyName] = value
dynamic entity=new ExpandoObject();
(实体作为IDictionary)[values[j].EntityPropertyName]=value
接下来是很长的答案。 反射在很多情况下都很好,在某些情况下很可怕,但在几乎所有情况下都很慢

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

我想我演示了其中之一:使用编译的表达式树。请注意,表达式生成也相当昂贵,因此将生成的委托缓存在字典中非常重要(例如):

表达式树是在.NET35中引入的,用于许多事情。在这里,我使用它们构建一个属性设置器表达式,然后将其编译为委托

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

   }
}
使用系统;
使用System.Linq.Expressions;
名称空间差异操作模式策略
{
类TestClass
{
公共字符串XY
{
得到;
设置
}
}
类委托工厂
{
公共静态操作GenerateSetPropertyActionForControl(
)
{
return(inst,val)=>((TestClass)inst.XY=(string)val;
}
公共静态操作生成带有反射的属性操作(
类型类型,
字符串属性
)
{
var propertyInfo=type.GetProperty(属性);
return(inst,val)=>propertyInfo.SetValue(inst,val,null);
}
公共静态操作使用LinqExpression生成SetProperty操作(
类型类型,
字符串属性
)
{
var propertyInfo=type.GetProperty(属性);
var propertyType=propertyInfo.propertyType;
var instanceParameter=Expression.Parameter(typeof(object),“instance”);
var valueParameter=表达式参数(类型(对象),“值”);
var lambda=表达式.lambda(
表达式.赋值(
Expression.Property(Expression.Convert(instanceParameter,类型),propertyInfo),
Expression.Convert(valueParameter,propertyType)),
瞬时参数计,
参数值
);
返回lambda.Compile();
}
}
静态类程序
{
静态空隙时间(
字符串标记,
对象实例,
对象值,
行动
)
{
//冷运行
行动(实例、价值);
var then=DateTime.Now;
常数整数计数=2000000;
对于(var iter=0;iter
开源框架ImpromptuInterface具有基于使用DLR而不是反射的字符串调用的方法,并且运行速度也比反射快

Impromptu.InvokeSet(localeEntity, values[j].EntityPropertyName,value);

对于FuleSnabel的答案,您可以大大加快速度(有时在我的测试中速度是原来的两倍)。在一些测试中,其速度与对照溶液一样快:

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();
}
公共静态操作GenerateSetPropertyActionWithLinqExpression2(类型,字符串属性){
PropertyInfo pi=type.GetProperty(属性,BindingFlags.Instance | BindingFlags.Public);
MethodInfo mi=pi.GetSetMethod();
类型propertyType=pi.propertyType;
var instance=Expression.Parameter(typeof(Object),“instance”);