缓存IEnumerable vs List以进行延迟初始化

时间:2014-08-27 15:02:43

标签: c# .net linq caching

我有一个简单的缓存类,可以检索并存储您传递给它的任何数据。该类具有的唯一操作是“Get(字符串键)”和“Store(字符串键,对象数据)”。我使用这个类存储昂贵的对象并快速检索它们。

想象一下,我想存储一个数组。据我所知,IEnumerable实现本质上是懒惰实例化的。我的问题是:如果我将一个IEnumerable变量存储到该Cache类(即LINQ查询的结果集),那么这个类是否会被存储并处理其所有元素,或者每当我检索到存储的IEnumerable时我将不得不经历所有处理隐含生成IEnumerable?我应该使用“ToList()”来触发初始化吗?

注意:我无法访问此Cache类的源代码,我只知道它存储和检索对象。

1 个答案:

答案 0 :(得分:3)

IEnumerable是一个接口,而不是一个类。接口背后的实现定义了它的行为。

如果您在IEnemerable<>上调用ToList()你得到一个List<>,还有一个IEnumerable<>当List实现该接口时。

将指针存储为IEnumerable<>迭代它与迭代列表相同。

如果IEnumerable<>是一个迭代器的结果,每次IEnumerable<>访问您执行实现。

实施例: 采取以下功能:

public IEnumerable<int> Generator(int max)
{
   for (var i = 0; i < max; i++)
   {
       yield return someExpensiveFunction();
   }
}

将其用作

var cache = Generator(100);

for (var i = 0; i < 2; i++)
{
   foreach (var i in cache)
   {
      //ops
   }
}

这将评估Generator(== IEnumerable&lt;&gt;)两次。

var cache = Generator(100).ToList();

for(var i = 0; i < 2; i++
{
   foreach(var i in cache)
   {
      //ops
   }
}

这将仅评估Generator(== IENumerable&lt;&gt;)一次。

即。缓存IEnumerable&lt;&gt;如果你做到具体的话,那就不贵了。通过调用ToArray(),ToList()等就可以了。

圆顶附加指南。如果将可枚举转换为列表并存储它们,则将存储变量声明为列表是一种很好的做法。这是为了向您的用户和/或同事记录它的存储模型。 公共类/接口上的函数或属性的结果应该是Collection

class X
{
   private List<int> _cache;

   public void UpdateCache(IEnumerable<int> items)
   {
     _cache = items.ToList();
   }

   public ICollection<T> Cache
   {
      get{ return _cache; }
   }

   //even better
   public ReadOnlyCollection<T> Items
   {
      get { return new ReadonlyCollection(_cache); }
   }
}