如何创建无法进行多次枚举的IEnumerable <t>?</t>

时间:2011-11-30 04:09:48

标签: c# ienumerable

当我枚举IEnumerable两次时,Resharper抱怨Possible multiple enumerations of IEnumerable。我知道,在某些情况下,当你枚举两次时会出现DB查询,你会得到一个异常。

我想在测试中重现这种行为。所以,我基本上想要抛出以下函数(因为有多个枚举):

    private void MultipleEnumerations(IEnumerable<string> enumerable)
    {
        MessageBox.Show(enumerable.Count().ToString());
        MessageBox.Show(enumerable.Count().ToString());
    }

我应该传递给它什么?所有列表,集合等都可以使用多个枚举。 即便是这种IEnumerable也没有例外:

    private IEnumerable<string> GetIEnumerable()
    {
        yield return "a";
        yield return "b";
    }

感谢。

3 个答案:

答案 0 :(得分:3)

您可能只想要一个自定义类:

public class OneShotEnumerable<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> _source;
    private bool _shouldThrow = false;

    public OneShotEnumerable(IEnumerable<T> source)
    {
        this._source = source;
    }

    public IEnumerator<T> GetEnumerator()
    {
        if (_shouldThrow) throw new InvalidOperationException();
        _shouldThrow = true;

        return _source.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

答案 1 :(得分:2)

创建自己的实现IEnumerable<T>的类,如果两次调用GetEnumerator()则抛出异常(使用布尔实例字段)。

或者,创建一个使用标志字段的迭代器,以确保它不能被调用两次(枚举迭代器两次将执行整个方法两次)。

答案 2 :(得分:1)

我从John Gietzen的答案中复制的自定义类(带有一些更正)可以与扩展方法结合使用,创建一种非常简单的方法来实现这一目标。

public class OneShotEnumerable<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> source;
    private bool shouldThrow = false;

    public OneShotEnumerable(IEnumerable<T> source)
    {
        this.source = source;
    }

    public IEnumerator<T> GetEnumerator()
    {
        if (shouldThrow) 
            throw new InvalidOperationException("This enumerable has already been enumerated.");

        shouldThrow = true;

        return this.source.GetEnumerator();
    }
}

public static clas OneShotEnumerableExtension
{
    public static IEnumerable<T> SingleUse<T>(this IEnumerable<T> source)
    {
#if (DEBUG)
        return new OneShotEnumerableExtension(source);
#else
        return source;
#endif
    }
}

然后,您只需执行

即可将某些内容传递给之前的方法
MultipleEnumerations(MyEnumerable.SingleUse());