2011-01-21 9 views
1

辞書を使用する私はIEnumerableをループし、そのたびにフィルター辞書に従ってフィルターを適用します。 FilterType enumは、フィルタを適用するフィールドを決定し、文字列はフリーテキストフィルタそのものです。同じIEnumerableでループするLINQクエリ - 何が欠けていますか?

問題は、複数のフィルタを辞書に追加すると(つまり、FilterType.CustomerとFilterType.Nameフィルタの両方)、フィルタはCustomerフィールドとNameフィールドの両方に適用されますが、フリーテキストフィルタ追加された最初のフィルタから取得されます。私。次のコードでは、nameFilterBox.TextはLINQクエリのNameフィールドとCustomerフィールドの両方に適用されますが、customerFilterBox.Textはまったく適用されません。したがって、辞書のFilterType部分は2回読み込まれますが、文字列フィルタは最初のものからのみ読み込まれます。

なぜこれが起こっているのか分かりません。

static IEnumerable<Jobb> jobQuery = GetInitialJobQuery(); 

Dictionary<FilterType, string> filters = new Dictionary<FilterType, string>(); 
filters.Add(FilterType.Name, nameFilterBox.Text); 
filters.Add(FilterType.Customer, customerFilterBox.Text); 

foreach (var filter in filters) 
{ 
    switch (filter.Key) 
    { 
     case FilterType.Customer: 
      jobQuery = jobQuery.Where(x => x.KUNDREF != null && 
         x.KUNDREF.ToLower().Contains(filter.Value.ToLower())); 
      break; 

     case FilterType.Name: 
      jobQuery = jobQuery.Where(x => x.JOBBESKR != null && 
         x.JOBBESKR.ToLower().Contains(filter.Value.ToLower())); 
      break; 
    } 
} 
+0

、「社内の誰もがより読みやすい/説明的な名前を使用する可能性を検討していますKUNDREF "と" JOBBESKR "? – Timwi

+1

スウェーデン語を知っていれば記述的です;) – jgauffin

答えて

3

これはforeach loop variable captureのバグです。あなたのラムダは、あなたが考えるものではなく、filtersの最後の値で動作します。

回避策はforeachループ内で新しい変数を宣言することです:あなたはラムダの内部のみfilter.Valueを使用するので、

foreach (var filterForeach in filters) 
{ 
    var filter = filterForeach; // for the lambdas 
    switch (filter.Key) 
    { 
     case FilterType.Customer: 
      jobQuery = jobQuery.Where(x => x.KUNDREF != null && 
         x.KUNDREF.ToLower().Contains(filter.Value.ToLower())); 
      break; 

     case FilterType.Name: 
      jobQuery = jobQuery.Where(x => x.JOBBESKR != null && 
         x.JOBBESKR.ToLower().Contains(filter.Value.ToLower())); 
      break; 
    } 
} 

また、あなたもこれを行うことができます:

foreach (var filter in filters) 
{ 
    var value = filter.Value.ToLower(); // for the lambdas 
    switch (filter.Key) 
    { 
     case FilterType.Customer: 
      jobQuery = jobQuery.Where(x => x.KUNDREF != null && 
         x.KUNDREF.ToLower().Contains(value)); 
      break; 

     case FilterType.Name: 
      jobQuery = jobQuery.Where(x => x.JOBBESKR != null && 
         x.JOBBESKR.ToLower().Contains(value)); 
      break; 
    } 
} 

エリックリッペルトこれについてのブログはClosing over the loop variable considered harmfulです。

+0

+説明、解答、参考に答えてください! –

1

私は正確にはわかりませんが、値が列挙子からどのように読み込まれるかと関係があり、ラムダのクロージャーで終わることはありません。値はループの後に使用されるので、列挙子のCurrentプロパティに残っている値、つまり最後の項目を使用します。

それはクロージャで終わる作るために、ローカル変数に値をコピーしてください:無関係なコメントとして

string value = filter.Value.ToLower(); 
switch (filter.Key) { 
    case FilterType.Customer: 
    jobQuery = jobQuery 
     .Where(x => x.KUNDREF != null && x.KUNDREF.ToLower().Contains(value)); 
    break; 
case FilterType.Name: { 
    jobQuery = jobQuery 
    .Where(x => x.JOBBESKR != null && x.JOBBESKR.ToLower().Contains(value)); 
    break; 
} 
関連する問題