【发布时间】:2020-05-15 18:52:25
【问题描述】:
我目前正在实施一些动态过滤/排序,并认为做一个基准来了解情况是个好主意。
首先,这是创建充当“getter”的表达式的方法:
public static Expression<Func<TEntity, object>> GetPropertyGetter(string propertyName, bool useCache = false)
{
if (useCache && _propertyGetters.ContainsKey(propertyName))
return _propertyGetters[propertyName];
var entityType = typeof(TEntity);
var property = entityType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (property == null)
throw new Exception($"Property {propertyName} was not found in entity {entityType.Name}");
var param = Expression.Parameter(typeof(TEntity));
var prop = Expression.Property(param, propertyName);
var convertedProp = Expression.Convert(prop, typeof(object));
var expr = Expression.Lambda<Func<TEntity, object>>(convertedProp, param);
if (useCache)
{
_propertyGetters.Add(propertyName, expr);
}
return expr;
}
这是基准:
public class OrderBy
{
private readonly List<Entry> _entries;
public OrderBy()
{
_entries = new List<Entry>();
for (int i = 0; i < 1_000_000; i++)
{
_entries.Add(new Entry($"Title {i}", i));
}
}
[Benchmark(Baseline = true)]
public List<Entry> SearchTitle()
{
return _entries.AsQueryable().OrderByDescending(p => p.Title).ToList();
}
[Benchmark]
public List<Entry> SearchTitleDynamicallyWithoutCache()
{
var expr = DynamicExpressions<Entry>.GetPropertyGetter("Title");
return _entries.AsQueryable().OrderByDescending(expr).ToList();
}
[Benchmark]
public List<Entry> SearchTitleDynamicallyWithCache()
{
var expr = DynamicExpressions<Entry>.GetPropertyGetter("Title", useCache: true);
return _entries.AsQueryable().OrderByDescending(expr).ToList();
}
}
public class Entry
{
public string Title { get; set; }
public int Number { get; set; }
public Entry(string title, int number)
{
Title = title;
Number = number;
}
}
所以我的问题是,为什么创建表达式(使用反射来获取属性)比直接访问 (p => p.Title) 更快?
【问题讨论】:
-
从技术上讲,这些都是所有表达式。您必须查看为它们中的每一个生成的表达式树,以了解编译器自动为您生成的表达式树有什么不同。
-
查看生成的IL或者粘贴到sharplab中。它将向您显示编译器为您的 lambda 创建的所有表达式。然后将其与您手动获得的内容进行比较
标签: c# .net-core benchmarking expression-trees