迭代器块的延迟加载行为导致缓存数据时出现困难。考虑以下简单测试程序:
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()
来存储已计算出的数据?
LoadDataFromDatabase
函数需要加载多少数据?在应用程序的生命周期内,它是否需要更改?如果答案是“很少”且“不需要更改”,那么为了简单起见,你应该将数据存储为列表。 - Michael Graczyk.ToList()
是否是解决延迟评估的标准方法,或者是否有更推荐的方法(例如,我可以在迭代器块方法上放置某个属性来告诉C#不要进行延迟评估)。 - tenfourToList
应该完全没问题。至于惰性求值,编译器只是将您写入迭代器块中的逻辑构建成状态机。在这种情况下,“急切”的求值将准确地将数据存储在列表中。因此,要么在迭代器块的结果上调用ToList
,要么只需修改您的LoadFromDataBase
方法以填充列表,而不是生成枚举。 - Michael Graczyk