65.9K
CodeProject 正在变化。 阅读更多。
Home

使用表达式树转储对象

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2010年8月2日

CPOL

1分钟阅读

viewsIcon

30182

使用表达式树转储对象。

不,我并非建议去除对象。

我的一个同事被问到,我是否知道一种方法,可以将未知类型对象的列表转储到DataTable中,其性能比他正在使用的方法更好。

被转储的对象通常具有十几个属性,但为了这篇文章的方便,让我们假设它们看起来像这样:

class SomeClass
{
    public int Property1 { get; set; }
    public long Property2 { get; set; }
    public string Property3 { get; set; }
    public object Property4 { get; set; }
    public DateTimeOffset Property5 { get; set; }
}

他正在使用的代码如下所示:

var properties = objectType.GetProperties();

foreach (object obj in objects)
{
    foreach (var property in properties)
    {
        property.GetValue(obj, null);
    }
}

对于包含一百万个对象的列表,在我的机器上这大约需要 6000 毫秒。

我立即想到了表达式树

如果在编译时知道对象的类型,它将类似于这样:

Expression<Func<SomeClass, int>> expression = o => o.Property1;
var compiled = expression.Compile();
var propertyValue = compiled.Invoke(obj);

但是,在编译时,对象的类型以及其属性的类型是未知的。因此,对于每个属性,我们将需要一个这样的表达式树:

Expression<Func<object, object>> expression = o => ((SomeClass)o).Property1;

前面的表达式获取将类型为object的参数转换为对象类型的属性的值。结果也必须转换为类型object,因为结果的类型必须与表达式的返回值类型匹配。

对于相同类型的对象,属性访问器的集合将按这种方式构建:

var compiledExpressions = (from property in properties
                           let objectParameter = Expression.Parameter(typeof(object), "o")
                           select
                             Expression.Lambda<Func<object, object>>(
                                 Expression.Convert(
                                     Expression.Property(
                                         Expression.Convert(
                                             objectParameter,
                                             objectType
                                         ),
                                         property
                                     ),
                                     typeof(object)
                                 ),
                                 objectParameter
                             ).Compile()).ToArray();

看起来有点复杂,但是使用这段代码读取同一对象集中所有对象的全部属性:

foreach (object obj in objects)
{
    foreach (var compiledExpression in compiledExpressions)
    {
        compiledExpression(obj);
    }
}

在我的机器上大约需要 150 毫秒。

没错,是之前时间的 2.5%。

 

© . All rights reserved.