【问题标题】:Reflection: Setting properties of lots of objects using Dynamic Methods反射:使用动态方法设置大量对象的属性
【发布时间】:2012-05-16 14:34:37
【问题描述】:

所以我有数千个通用类型 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);
    }
}

reader 是一个 DataReader。我遇到的问题是 prop.SetValue 非常慢(消耗了总执行时间的 50%),I've been told 使用动态方法或表达式树,我尝试使用表达式树但是从什么我知道我必须为我要设置的每个值生成一棵树,这不是很好。 所以动态方法是另一种选择。理想情况下,我需要创建一个方法 SetProp(object, propertyName, value),我可以一遍又一遍地重用它。

【问题讨论】:

  • 就个人而言,我会说“不要在每个单元格中使用 GetOrdinal”,尽管这并不重要 - 但是,因为这显然是“数据阅读器” " 属性名和列名 1:1 匹配的代码,我真的建议你看看 dapper-dot-net;它专为正是这种场景而设计,并且使数据访问变得轻松。它是我们在 Stack Overflow 上编写并广泛用于大部分数据访问的工具。

标签: c# reflection


【解决方案1】:

看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 是因为我不能投票 10 次,快速浏览一下效果很好...我必须更新我的代码!
  • 还有ObjectAccessor 用于逐个对象的代码;我还应该注意,它也支持dynamic API(因此您可以使用它与运行时属性绑定的对象通信)
【解决方案2】:

我尝试使用表达式树,但据我了解,我必须为要设置的每个值生成一棵树,这不是很好。

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

我在 MiscUtil 中有一个 PropertyCopy 类,它的作用非常相似 - 您可能想从中获得灵感。

或者,从 .NET 4 开始,您可以构建一个单独的 Block 表达式树,它会执行所有属性设置。

【讨论】:

  • 我不认为我使用该解决方案,但我一定会检查它,谢谢!
【解决方案3】:

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

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() 来使其更快。

【讨论】:

    猜你喜欢
    • 2010-10-11
    • 1970-01-01
    • 2013-10-08
    • 2023-03-18
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 2015-10-13
    相关资源
    最近更新 更多