我有一个泛型扩展方法,它接受一个Expression参数。该参数用于构建,编译和缓存表达式树。这一部分都运作良好(表达式只编译一次)。
但是当我分析应用程序时,我会在调用代码中看到在Expression.Lambda和Expression.Property中花费的时间。这是预期的还是我在定义/编译表达式时做错了什么?
这是所涉及代码的简化版本:
namespace Example
{
public class Caller
{
public void SetPropertyX(MyTypedDataRow dataRow, string value)
{
// Inside this method, the profiler shows time spent in Expression.Lambda and Expression.Property
// even when the same property is reused and the compiled expression stored in the dictionary of
// DataRowExpressionHelper is used.
dataRow.Set(x => x.PropertyX, value);
}
}
public static class DataRowExtensions
{
public static void Set<TRow, TValue>(this TRow row, Expression<Func<TRow, TValue>> property, TValue value) where TRow : DataRow
{
DataRowExpressionHelper<TRow>.Set(row, property, value);
}
}
internal static class DataRowExpressionHelper<TRow> where TRow : DataRow
{
private static Dictionary<string, object> _propertySetters = new Dictionary<string, object>();
internal static void Set<TValue>(TRow row, Expression<Func<TRow, TValue>> property, TValue value)
{
var propertyInfo = (PropertyInfo) ((MemberExpression) property.Body).Member;
var propertyName = propertyInfo.Name;
Action<TRow, TValue> propertySetter;
object untypedSetter;
if (_propertySetters != null && _propertySetters.TryGetValue(propertyName, out untypedSetter))
{
propertySetter = (Action<TRow, TValue>)untypedSetter;
}
else
{
var targetRow = Expression.Parameter(typeof(TRow), "targetRow");
var newValue = Expression.Parameter(typeof(TValue), "newValue");
propertySetter = Expression.Lambda<Action<TRow, TValue>>(
Expression.Block(/* Logic here */),
// Input parameters
targetRow,
newValue
).Compile();
var updatedPropertySetters = new Dictionary<string, object>(_propertySetters);
updatedPropertySetters[propertyName] = propertySetter;
_propertySetters = updatedPropertySetters;
}
propertySetter.Invoke(row, value);
}
}
答案 0 :(得分:0)
如果您查看调用者的反编译代码,您会看到如下内容:
public void SetPropertyX(MyTypedDataRow dataRow, string value)
{
var parameter = Expression.Parameter("x", typeof(MyTypedDataRow));
dataRow.Set(Expression.Lambda<Func<MyTypedDataRow, string>>(Expression.Property(parameter, "PropertyX"), parameter) , value);
}
正如您所见,您的lambda是内联构造的。
不幸的是,对于一个被称为批量的方法,这会产生很大的性能影响。在这种情况下,要么将表达式树(例如x =&gt; x.PropertyX)保存到静态字段,要么如果它们太多,则按属性名称缓存它们(如果您的columntype数量有限,那么也是按列类型)