2009-07-07 23 views
0

私は同様の問題を抱えていますQuestion 222511私はMemberInit式を使用してコンストラクタに追加することができます...実装しようとしていますJohn Skeet's回答を実行しようとしていますが、パフォーマンスの違い。ここでは、コードの一部である:MemberInitとのパフォーマンスの違い

// 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

あなたのタイトルにタイプミスがあります:あなたはまた、このように、LINQクエリを使用して、ループ全体を置き換えることができ

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

EDIT:次のように使用します(performa * n * ce) – SLaks

+0

メソッドAのコード全体を投稿できますか? – SLaks

+0

これはProperty Initの例です:Balance = loanNote.Balance、APR = loanNote.APRなど... – bytebender

答えて

1

それは反射(GetPropertiesコール)を使用しているため、第二の方法を実行するために遅くなります。

あなたはそれを何度も呼び出している場合、あなたはこのようなGetPropertiesの結果をキャッシュすることができますが:

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

これは一度だけのタイプごとにGetPropertiesを呼び出します。

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) 
     ) 
    ); 
+0

私はあなたの提案を試みたが、それは何の違いもありません...私はコードをステップし、BuildJoinResultSelectorは一度だけ呼び出されているため、GetPropertiesは一度呼び出されています。だからそれにはそれほどの効果があるはずです。ありがとう... – bytebender

+0

式を構築するときや実行するときに遅れが生じていますか? – SLaks

+0

実行中です。 – bytebender

関連する問題