Is there a way to Memorize or Materialize an IEnumerable?

前端 未结 3 1687
孤街浪徒
孤街浪徒 2020-12-06 02:30

When given an d you could be dealing with a fixed sequence like a list or array, an AST that will enumerate some external datasource, or even an AST on some exi

相关标签:
3条回答
  • 2020-12-06 02:51

    Check out this blog post I wrote a couple of years ago: http://www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist

    In it, I define a method called ToLazyList that effectively does what you're looking for.

    As written, it will eventually make a full copy of the input sequence, although you could tweak it so that instances of IList don't get wrapped in a LazyList, which would prevent this from happening (this action, however, would carry with it the assumption that any IList you get is already effectively memoized).

    0 讨论(0)
  • 2020-12-06 02:55

    Easy enough:

    public static IList<TSource> Materialize<TSource>(this IEnumerable<TSource> source)
    {
        if (source is IList<TSource>)
        {
            // Already a list, use it as is
            return (IList<TSource>)source;
        }
        else
        {
            // Not a list, materialize it to a list
            return source.ToList();
        }
    }
    
    0 讨论(0)
  • 2020-12-06 02:57

    Original answer:

    Same as Thomas's answer, just a bit better according to me:

    public static ICollection<T> Materialize<T>(this IEnumerable<T> source)
    {
        // Null check...
        return source as ICollection<T> ?? source.ToList();
    }
    

    Please note that this tend to return the existing collection itself if its a valid collection type, or produces a new collection otherwise. While the two are subtly different, I don't think it could be an issue.


    Edit:

    Today this is a better solution:

    public static IReadOnlyCollection<T> Materialize<T>(this IEnumerable<T> source)
    {
        // Null check...
        switch (source)
        {
            case ICollection<T> collection:
                return new ReadOnlyCollectionAdapter<T>(collection);
    
            case IReadOnlyCollection<T> readOnlyCollection:
                return readOnlyCollection;
    
            default:
                return source.ToList();
        }
    }
    
    public class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
    {
        readonly ICollection<T> m_source;
    
        public ReadOnlyCollectionAdapter(ICollection<T> source) => m_source = source;
    
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    
        public int Count => m_source.Count;
    
        public IEnumerator<T> GetEnumerator() => m_source.GetEnumerator();
    }
    
    0 讨论(0)
提交回复
热议问题