3

イテレータ ブロックの遅延読み込み動作により、データのキャッシュに問題が発生しています。次の小さなテスト プログラムを検討してください。

class Program
{
    static IEnumerable<int> LoadDataFromDatabase()
    {
        Console.WriteLine("Hitting database....");
        yield return 13;
    }

    static IEnumerable<int> _cachedData = null;
    static IEnumerable<int> CachedData
    {
        get
        {
            if (_cachedData == null)
            {
                _cachedData = LoadDataFromDatabase();
            }
            return _cachedData;
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine(string.Format("Collection contains {0} items.", CachedData.Count()));
        Console.WriteLine(string.Format("Collection contains {0} items.", CachedData.Count()));
    }
}

これへの出力は

データベースをヒットしています....

コレクションには 1 個のアイテムが含まれています。

データベースをヒットしています....

コレクションには 1 個のアイテムが含まれています。

データベースを 1 回だけヒットしたい (したがってキャッシュ)LoadDataFromDatabase()が、イテレータ ブロックであるため、実際のデータベース呼び出しはキャッシュされるものであり、データではありません。

このシナリオでのベスト プラクティスは何ですか? _cachedData = LoadDataFromDatabase().ToList()評価されたデータを保存するだけでいいですか?

4

1 に答える 1

3

追加でき.ToList()ます:

static IEnumerable<int> CachedData
{
    get
    {
        if (_cachedData == null)
        {
            _cachedData = LoadDataFromDatabase().ToList();
        }
        return _cachedData;
    }
}

不利な点は、リストに 100.000 個のアイテムがあり、次のようにする場合です。

var list1 = CachedData.Take(2).Sum();
var list2 = CachedData.Take(3).Sum();
var list3 = CachedData.Take(1).Sum();

... リストの 100.000 アイテムをロードします。

解決策は、事前ではなく反復LazyListに Enumerable をキャッシュするa を実装することです。に置き換えるだけです。.ToList().ToLazyList()

これにより、最適なオプションが得られます。

  • 最初の 3 つのアイテムは合計 1 回だけロードされます。
  • アイテム 4 は一度もロードされていません

遅延リストの実装例はこちらです。

于 2013-10-12T21:18:04.773 に答える