What is a good way to to indicate an IEnumerable is “slow” or “fast”?

▼魔方 西西 提交于 2019-12-05 05:37:17

Conversely, would returning IQueryable instead of IEnumerable be a good way to indicate "this is slow"?

No, IQueryable<T> inherent from IEnumerable<T>... and the problem with IEnumerable<T>T is that it could be IQueryable<T> with a a huge side affect when iterating, like query a remote database or something like that.

Funny isn't it?

You probably should be asking about IEnumerable<T> V.S. List<T> which the second one definitely has the data in it, and doesn't need to get it from somewhere else.

If you want to guarantee that iteration will not contain any surprises then I agree, expose a T[] - the enumerator for it cannot be overridden as you cannot inherit from arrays. Iteration is also side-effect free, the same cannot be said for IEnumerable<T>.

However, I would disagree that exposing an array expresses this message, which is more important (in my opinion). The performance of something can never really be expressed in code, unless you start naming stuff CheapIteration or ExpensiveIteration.

On the other side of the coin, with an array you simply move the performance problem of on-demand iteration to the point of populating the array. This is guaranteed to hit the performance problem fully as it will be a full iteration of whatever supplies the array contents. In an IEnumerable<T> if iteration stops, so does the performance problem - the fastest code is the code that doesn't run.

After thinking about this some more, it seems the problem/question really centers on the behavior/performance of IEnumerator.MoveNext(). Using Visual Studio 2012, I was able to create async versions of IEnumerator and IEnumerable:

public interface IAsyncEnumerator<T> : IDisposable
{
    Task<T> CurrentAsync { get; }
    Task<bool> MoveNextAsync();
    Task ResetAsync();
}

public interface IAsyncEnumerable<T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator();
}

A disadvantage to this approach is there isn't a lot of language support; the above won't work with foreach. But, an extension method can ease the pain:

public static class EnumeratorExtensions
{
    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
    {
        using (var enumerator = enumerable.GetEnumerator())
        {
            while (enumerator.MoveNext())
                action(enumerator.Current);
        }
    }

    public static async Task ForEachAsync<T>(this IAsyncEnumerable<T> enumerable, Action<T> action)
    {
        using (var enumerator = enumerable.GetAsyncEnumerator())
        {
            while (await enumerator.MoveNextAsync())
                action(await enumerator.CurrentAsync);
        }
    }
}

I usually use properties for returning 'quick' enumerations and methods for 'slow'.

Your problem is an argument for using asynchronous approach and design as much as possible. Then it really doesn't matter how long the enumeration takes, as the UI is responsive and the user happy ;-)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!