反射:使用动态方法设置大量对象的属性

时间:2012-05-16 14:34:38

标签: c# reflection

所以我有数以千计的通用类型T的对象,我想将它们转换为我得到的对象数组。 所以我必须得到属性列表T,并为每个属性设置值到数组上相应的对象

for (int i = 0; reader.Read(); i++)
{
    T tmp = (T)Activator.CreateInstance(typeof(T));
    foreach (var prop in properties)
    {         
        prop.SetValue(tmp, reader.GetValue(reader.GetOrdinal(prop.Name)), null);
    }
}

读者是一个DataReader。我遇到的问题是 prop.SetValue 很慢(占总执行时间的50%),I've been told使用动态方法或表达式树,我尝试使用表达式树但是根据我的理解,我必须为我想要设置的每个值生成一个树,这不会那么好。 所以动态方法是另一种选择。理想情况下,我需要创建一个方法 SetProp(object,propertyName,value),我可以一遍又一遍地重复使用。

3 个答案:

答案 0 :(得分:4)

FastMember;要么“按原样”使用它,要么窃取所有代码(DynamicMethod等)。它完成了所有这些,内置了反射缓存等。示例用法:

var accessor = TypeAccessor.Create(typeof(T)); 
for (int i = 0; reader.Read(); i++)
{
    T tmp = (T)Activator.CreateInstance(typeof(T));
    foreach (var prop in properties)
    {         
        accessor[tmp, propName] = newValue; // fill in name/value here
    }
}

或者 - 使用像dapper-dot-net这样的东西,处理所有物化(因为这显然是数据访问代码)。

答案 1 :(得分:3)

  

我尝试使用表达式树,但据我所知,我必须为我想要设置的每个值生成一个树,这不会那么好。

为什么不呢?您基本上通过为List<Tuple<string, Action<object>>>中的每个属性创建(然后编译)表达式树来构建T。然后迭代列表并获取每个属性的项目,然后调用相应的操作。

我在MiscUtil中有一个PropertyCopy课程,它做了类似的事情 - 你可能想看看它是否有灵感。

或者,从.NET 4开始,您可以构建一个{em} all 属性设置的Block表达式树。

答案 2 :(得分:0)

您可以为每个属性创建一个表达式树 只需将该值作为参数:

var instance = Expression.Parameter(typeof(T));
var value = Expression.Parameter(typeof(object));
var setter = Expression.Lambda(
    Expression.SetProperty(instance, Expression.Cast(value, prop.PropertyType)),
    instance, value
);

您可以为每个实例类型创建和编译这些表达式树(通常在static generic class中)。

当你接触它时,你可以通过编译另一个表达式树而不是Activator.CreateInstance()来使它更快。