与 MemberInit 表达式的性能差异
我正在处理与 问题 222511 类似的问题,我确实需要使用MemberInit 表达式,这样我就可以将它们添加到构造函数中...我正在尝试实现 John Skeet 的 答案,但是我遇到了很大的性能差异。 这是一些代码:
// Method A:
// This work good, is fast and returns an un-executed query...
DataContext.LoanNote.Join<LoanNote, Customer, int, LoanNote>(
DataContext.Customers, loanNote => loanNote.PrimaryCustomerNumber, customer => customer.CustomerNumber,
(LoanNote loanNote, Customer customer) => new LoanNote()
{
AccountFeeBillAmount = loanNote.AccountFeeBillAmount,
AccountOpenDate = loanNote.AccountOpenDate,
// This goes on and on...
PrimaryCustomer = customer
});
// Method B:
// This on the other hand is a lot slower and I am not sure why...
var resultSelector = BuildJoinResultSelector<LoanNote, Customer, LoanNote("PrimaryCustomer").Compile();
DataContext.LoanNote.Join<LoanNote, Customer, int, LoanNote>(
DataContext.Customers, loanNote => loanNote.PrimaryCustomerNumber, customer => customer.CustomerNumber, resultSelector);
// The build MemberInitExpression method...
private static Expression<Func<TOuter, TInner, TResult>> BuildJoinResultSelector<TOuter, TInner, TResult>(string propertyName) where TResult : class
{
var result = default(Expression<Func<TOuter, TInner, TResult>>);
var resultType = typeof(TResult);
var outerType = typeof(TOuter);
var innerType = typeof(TInner);
var outer = Expression.Parameter(outerType, "outer");
var inner = Expression.Parameter(innerType, "inner");
var bindings = new List<MemberBinding>();
foreach (var property in resultType.GetProperties())
{
if (property.CanRead == false)
{
continue;
}
else if (property.CanWrite == false)
{
continue;
}
else if (property.Name == propertyName)
{
var condition = Expression.Condition(Expression.Equal(inner, Expression.Constant(null)), Expression.New(innerType), inner);
bindings.Add(Expression.Bind(property, condition));
}
else
{
bindings.Add(Expression.Bind(property, Expression.Property(outer, property)));
}
}
var memberInit = Expression.MemberInit(Expression.New(resultType), bindings);
result = Expression.Lambda<Func<TOuter, TInner, TResult>>(memberInit, outer, inner);
return result;
}
I am working a similar problem as Question 222511 I do need to use the MemberInit Expression so I can just add them to the constructor... I am trying to implement John Skeet's answer but I am running into a big performance difference. Here is some of the code:
// Method A:
// This work good, is fast and returns an un-executed query...
DataContext.LoanNote.Join<LoanNote, Customer, int, LoanNote>(
DataContext.Customers, loanNote => loanNote.PrimaryCustomerNumber, customer => customer.CustomerNumber,
(LoanNote loanNote, Customer customer) => new LoanNote()
{
AccountFeeBillAmount = loanNote.AccountFeeBillAmount,
AccountOpenDate = loanNote.AccountOpenDate,
// This goes on and on...
PrimaryCustomer = customer
});
// Method B:
// This on the other hand is a lot slower and I am not sure why...
var resultSelector = BuildJoinResultSelector<LoanNote, Customer, LoanNote("PrimaryCustomer").Compile();
DataContext.LoanNote.Join<LoanNote, Customer, int, LoanNote>(
DataContext.Customers, loanNote => loanNote.PrimaryCustomerNumber, customer => customer.CustomerNumber, resultSelector);
// The build MemberInitExpression method...
private static Expression<Func<TOuter, TInner, TResult>> BuildJoinResultSelector<TOuter, TInner, TResult>(string propertyName) where TResult : class
{
var result = default(Expression<Func<TOuter, TInner, TResult>>);
var resultType = typeof(TResult);
var outerType = typeof(TOuter);
var innerType = typeof(TInner);
var outer = Expression.Parameter(outerType, "outer");
var inner = Expression.Parameter(innerType, "inner");
var bindings = new List<MemberBinding>();
foreach (var property in resultType.GetProperties())
{
if (property.CanRead == false)
{
continue;
}
else if (property.CanWrite == false)
{
continue;
}
else if (property.Name == propertyName)
{
var condition = Expression.Condition(Expression.Equal(inner, Expression.Constant(null)), Expression.New(innerType), inner);
bindings.Add(Expression.Bind(property, condition));
}
else
{
bindings.Add(Expression.Bind(property, Expression.Property(outer, property)));
}
}
var memberInit = Expression.MemberInit(Expression.New(resultType), bindings);
result = Expression.Lambda<Func<TOuter, TInner, TResult>>(memberInit, outer, inner);
return result;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第二种方法的执行速度会较慢,因为它使用反射(
GetProperties
调用)。如果您多次调用它,您可以像这样缓存 GetProperties 的结果:
这将针对每种类型仅调用一次
GetProperties
; 像这样使用:编辑:
您还可以用 LINQ 查询替换整个循环,如下所示:
The second method will be slower to execute because it uses reflection (the
GetProperties
call).If you are calling it many times, you can cache the result of GetProperties like this:
This will call
GetProperties
just once per type; use like this:EDIT:
You can also replace your entire loop with a LINQ query, like this: