2011-08-11 15 views
3

私はユニットのテストの途中で、クエリ可能なアイテムを検索するための関数を書いています。私はちょうど私が1つのアイテムを取得することを主張する、私は方法が動作する場合、私は取得する必要があります。しかし、私は0アイテムを返す。私の方法では、遅延実行を使用し、返す前にToListを使用します。しかし、代わりにリストを直接操作して、ToListを繰り返し呼び出すメソッドを変更すると、正しい結果が得られます。遅延実行とToListの結果が異なる

遅延実行が即時実行と同じ結果をもたらすと想定するのは安全ではないと言うのは正しいですか?

これは私が実際に2 everything that begins with 2 should be foundはそれがないとfalseを返す、Valueが含まれている場合、それはチェックしていることがわかりますブレークポイントを設定した場合、それは0アイテム

class Program 
    { 

     static void Main(string[] args) 
     { 
      Dictionary<string, string> values = new Dictionary<string, string>() 
      { 
       { 
        "Prop1", 
        "*Value*" 
       }, 
       { 
        "Prop2", 
        "2*" 
       } 
      }; 
      List<InputItem> items =new List<InputItem>() 
      { 
       new InputItem() 
      }; 
      Console.WriteLine(Helper.SearchInputItems(items.AsQueryable(), values).Count); 
      Console.ReadLine(); 
     } 
    } 

    public class InputItem 
    { 
     public Dictionary<string, string> MappedValues = new Dictionary<string, string>() 
     { 
      { 
        "Prop1", 
        "This is a value that should be found" 
       }, 
       { 
        "Prop2", 
        "2 everything that begins with 2 should be found" 
       } 
     }; 
    } 
    public static class Helper 
    { 
     delegate bool Searcher(string input, string searchString); 
     /// <summary> 
     /// Searches the added input items. 
     /// </summary> 
     /// <param name="values">A dictionary of field names and the search pattern for that field.</param> 
     /// <returns>List of found InputItems.</returns> 
     public static List<InputItem> SearchInputItems(IQueryable<InputItem> inputItems, Dictionary<string, string> values) 
     { 
      foreach (var value in values) 
      { 
       string searchString = value.Value; 
       Searcher searcher; 
       if (searchString.StartsWith("*") && searchString.EndsWith("*")) 
       { 
        searcher = new Searcher(StringHelpers.Contains); 
        searchString = searchString.Substring(1); 
        searchString = searchString.Remove(searchString.Length - 1); 
       } 
       else if (searchString.EndsWith("*")) 
       { 
        searcher = new Searcher(StringHelpers.StartsWith); 
        searchString = searchString.Remove(searchString.Length - 1); 
       } 
       else 
       { 
        searcher = new Searcher(StringHelpers.Exact); 
       } 
       inputItems = inputItems.Where(c => 
        c.MappedValues.Any(x => x.Key == value.Key) && 
        searcher(c.MappedValues.First(x => x.Key == value.Key).Value, searchString) 
        ); 

      } 
      return inputItems.ToList(); 
     } 
    } 
    public static class StringHelpers 
    { 
     public static bool Contains(string input, string searchString) 
     { 
      return input.ToUpperInvariant().Contains(searchString.ToUpperInvariant()); 
     } 
     public static bool StartsWith(string input, string searchString) 
     { 
      return input.ToUpperInvariant().StartsWith(searchString.ToUpperInvariant()); 
     } 
     public static bool Exact(string input, string searchString) 
     { 
      return input.ToUpperInvariant() == searchString.ToUpperInvariant(); 
     } 
    } 

を返すことを実証するために小さなアプリです。だからWhere句のFirstOrDefaultが間違った項目を選択するように思えます

+0

投稿したコードは* working *コードですか?それが壊れている場合、どのように見えますか?メソッドのシグネチャは 'List 'を返すと言っているので、それをどのように遅延させるかを知るのは難しいですか?*入力データに 'ToList'を呼び出すことについて話していますか? –

+0

@Jonいいえ、投稿されたコードは意図したとおりに動作していません。それが動作するとき、私は最初の行を 'var inputItems = InputItemRepository.GetInputItems()。ToList;' –

+0

に変更します。それは完全にはっきりしていなかった。さて、InputItemRepositoryは実際に何を返すのですか?これは本当にデータベースに接続されているのですか?あなたは本当にこれを実証するためにあなたが持っているコードの量を減らすことができるはずです - あなたは本当にそれを失敗させるためにStartsWithとEndsWithの両方が必要ですか?すべてのマッピングとフィルタが必要ですか? –

答えて

3

さて、私はそれを持っています。それはcapturing the loop variableの古い問題です。ここで

 foreach (var value in values) 
     { 
      ... 
      inputItems = inputItems.Where(c => 
       c.MappedValues.Any(x => x.Key == value.Key) && 
       searcher(c.MappedValues.First(x => x.Key == value.Key).Value, 
               searchString) 
       ); 

     } 

あなたはそれが...実行し、ループの繰り返し処理としてその値が変化するとき、それは「valueの現在の値を」使用することを意味しており、ラムダ式内valueを使用しています。

は単純に使用します。

foreach (var valueIterationVariable in values) 
{ 
    var value = valueIterationVariable; 
    // code as before 
} 

と私はそれは大丈夫だろうと信じています。しかし、それは別の問題です。

私はIEnumerable<T>で動作していた理由を深く見ていませんでしたが、余分な延期が疑われます責任がある。

+0

これは素晴らしいことです。私は今まで知らなかった。この記事では、なぜこれが機能しないのかを明確に説明しています。 –