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 个项目。

我只想访问数据库一次(因此缓存),但因为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 项。

解决方案是在迭代时而不是提前实现缓存EnumerableLazyList的实现。只需替换为..ToList().ToLazyList()

这会产生最佳选择:

  • 前 3 个项目总共只加载了 1 次。
  • 项目 4 从未加载过

一个惰性列表的实现示例在这里

于 2013-10-12T21:18:04.773 回答