Performance Difference with MemberInit Expression

I am working with a similar problem Question 222511 I need to use MemberInit expression so that I can just add them to the constructor ... I am trying to insert John Skeet's answer , but I ran into a big difference in performance. Here are 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; } 
0
performance c # lambda linq
source share
1 answer

The second method will be slower to execute because it uses reflection (a call to GetProperties ).

If you call it many times, you can cache the result of GetProperties as follows:

 static class PropertiesCache<T> { public static readonly PropertyInfo[] Properties = typeof(T).GetProperties(); } 

This will call GetProperties only once for each type; use the following:

 foreach (var property in PropertiesCache<TResult>.Properties) { if(!property.CanRead || !property.CanWrite) continue; //... } 

EDIT

You can also replace the entire loop with a LINQ query as follows:

 var memberInit = Expression.MemberInit(Expression.New(typeof(TResult)), from property in PropertiesCache<TResult>.Properties where property.CanRead && property.CanWrite select Expression.Bind(property, property.Name == propertyName ? Expression.Coalesce(inner, Expression.New(innerType)) : Expression.Property(outer, property) ) ); 
+1
source share

All Articles