Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can mix the suggestions, you can implement an wrapper class, generics-based, that takes the IEnumerable and returns a new one that constructs a cache on each next, and reuses the partial cache as needed on further enumerations. It is not easy, but will create objects (in truth only for Iterators that construct objects on-the-fly) only once and as needed. The hardest part is to be sure when to switch from the partial cache back to the original enumerator and how to make it transactional (consistent). </p> <p>Update with tested code:</p> <pre><code>public interface ICachedEnumerable&lt;T&gt; : IEnumerable&lt;T&gt; { } internal class CachedEnumerable&lt;T&gt; : ICachedEnumerable&lt;T&gt; { private readonly List&lt;T&gt; cache = new List&lt;T&gt;(); private readonly IEnumerator&lt;T&gt; source; private bool sourceIsExhausted = false; public CachedEnumerable(IEnumerable&lt;T&gt; source) { this.source = source.GetEnumerator(); } public T Get(int where) { if (where &lt; 0) throw new InvalidOperationException(); SyncUntil(where); return cache[where]; } private void SyncUntil(int where) { lock (cache) { while (where &gt;= cache.Count &amp;&amp; !sourceIsExhausted) { sourceIsExhausted = source.MoveNext(); cache.Add(source.Current); } if (where &gt;= cache.Count) throw new InvalidOperationException(); } } public bool GoesBeyond(int where) { try { SyncUntil(where); return true; } catch (InvalidOperationException) { return false; } } public IEnumerator&lt;T&gt; GetEnumerator() { return new CachedEnumerator&lt;T&gt;(this); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new CachedEnumerator&lt;T&gt;(this); } private class CachedEnumerator&lt;T&gt; : IEnumerator&lt;T&gt;, System.Collections.IEnumerator { private readonly CachedEnumerable&lt;T&gt; parent; private int where; public CachedEnumerator(CachedEnumerable&lt;T&gt; parent) { this.parent = parent; Reset(); } public object Current { get { return Get(); } } public bool MoveNext() { if (parent.GoesBeyond(where)) { where++; return true; } return false; } public void Reset() { where = -1; } T IEnumerator&lt;T&gt;.Current { get { return Get(); } } private T Get() { return parent.Get(where); } public void Dispose() { } } } public static class CachedEnumerableExtensions { public static ICachedEnumerable&lt;T&gt; AsCachedEnumerable&lt;T&gt;(this IEnumerable&lt;T&gt; source) { return new CachedEnumerable&lt;T&gt;(source); } } </code></pre> <p>With this you can now add a new Test that shows it works:</p> <pre><code> [Test] public void Test3() { count = 0; ICachedEnumerable&lt;MyClass&gt; yieldResult = GetYieldResult(1).AsCachedEnumerable(); var firstGet = yieldResult.First(); var secondGet = yieldResult.First(); Assert.AreEqual(1, firstGet.Id); Assert.AreEqual(1, secondGet.Id); Assert.AreEqual(1, count);//calling "First()" 2 times, yieldResult is created 2 times Assert.AreSame(firstGet, secondGet);//and created different instances of each list item } </code></pre> <p>Code will be incorporated at my project <a href="http://github.com/monoman/MSBuild.NUnit" rel="nofollow">http://github.com/monoman/MSBuild.NUnit</a> , may later appear in the Managed.Commons project too</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload