IEnumerable实现打破了foreach

时间:2014-02-25 19:08:29

标签: c# linq foreach enumeration

我正在使用PDFNet库从PDF中提取对象,然后是OCR。我实例化我的Elements对象:

public class Processor
{
    public static int Main(string[] args)
    {
       Elements pdfPageElements = new Elements(pdfPage);
       ...

构造函数(在单独的类中)看起来像

internal class Elements : IEnumerator<Element>, IEnumerable<Element>
{
    private readonly int _position;
    private readonly ElementReader _pdfElements;
    private Element _current;

    public Elements(Page currentPage)
    {
        _pdfElements = new ElementReader();
        _pdfElements.Begin(currentPage);
        _position = 0;
    }

    ...

实例化pdfPageElements后,我回到Main()并使用Linq迭代集合项以获取我想要的PDF对象(在本例中为图像)。

var pdfPageImages = (from e in pdfPageElements
                     where
                         (e.GetType() == Element.Type.e_inline_image ||
                          e.GetType() == Element.Type.e_image)
                     select e);

PDFNet SDK按如下方式实现MoveNext()方法:

public bool MoveNext()
{
   if ((_current = _pdfElements.Next()) != null)
    {
        return true;
    }
    else
    {
        _pdfElements.Dispose();
         return false;
     }
 }

pdfPageImages很好地安顿下来; Console.WriteLine(pdfPageImages.Count());为我的测试PDF返回正确数量的图片。

但是当我通过pdfPageImages发送foreach loop时,我收到以下异常:

pdftron.Common.PDFNetException: Unknown exception.
 at pdftron.PDF.ElementReader.Next()
 at pdftron.Elements.MoveNext()
 at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
 at DM_PDFProcessor.Processor.Main(String[] args)

值得注意的是,PDFNet文档中指出:

Every call to ElementReader::Next() destroys the current Element. 
Therefore, an Element becomes invalid after subsequent 
ElementReader::Next() operation.

但是,一旦元素被读入IEnumerable pdfPageImages,它应该可以无限期地迭代(从我有限的理解)。


请注意,集合中的元素绝对 非空。任何想法为什么我一直得到例外?

1 个答案:

答案 0 :(得分:3)

请注意

var pdfPageImages = (from e in pdfPageElements
                     where
                         (e.GetType() == Element.Type.e_inline_image ||
                          e.GetType() == Element.Type.e_image)
                     select e);

被懒惰地评估。也就是说,每次枚举pdfPageImages时,也会枚举pdfPageElements。因此,如果构建Elements类以便实例只能枚举一次而不抛出,则可能需要缓存查询结果:

var pdfPageImages = (from e in pdfPageElements
                     where
                         (e.GetType() == Element.Type.e_inline_image ||
                          e.GetType() == Element.Type.e_image)
                     select e).ToList();