IEnumerable <string> System.ObjectDisposedException

时间:2017-03-20 13:31:15

标签: c#

在某些机器上,但在其他机器上没有,我使用此类获得System.ObjectDisposedException

class LogComparer
    {
        private string firstFile;
        private string secondFile;
        private IEnumerable<string> inFirstNotInSecond;
        private IEnumerable<string> inSecondNotInFirst;

        public LogComparer(string firstFile, string secondFile)
        {
            if (!File.Exists(firstFile) || !File.Exists(secondFile))
            {
                throw new ArgumentException("Input file location is not valid.");
            }
            this.firstFile = firstFile;
            this.secondFile = secondFile;
            GenerateDiff();
        }

        public string FirstFile
        {
            get
            {
                return firstFile;
            }
        }

        public bool IsEqual
        {
            get
            {
                return inFirstNotInSecond.SequenceEqual(inSecondNotInFirst);
            }
        }

        public string SecondFile
        {
            get
            {
                return secondFile;
            }
        }

        public IEnumerable<string> InFirstNotInSecond
        {
            get
            {
                return inFirstNotInSecond;
            }
        }

        public IEnumerable<string> InSecondNotInFirst
        {
            get
            {
                return inSecondNotInFirst;
            }
        }

        private void GenerateDiff()
        {
            var file1Lines = File.ReadLines(firstFile);
            var file2Lines = File.ReadLines(secondFile);

            inFirstNotInSecond = file1Lines.Except(file2Lines);
            inSecondNotInFirst = file2Lines.Except(file1Lines);
        }
    }
System.ObjectDisposedException: Cannot read from a closed TextReader.
ObjectName: 
   at System.IO.__Error.ReaderClosed()
   at System.IO.StreamReader.ReadLine()
   at System.IO.File.<InternalReadLines>d__0.MoveNext()
   at System.Linq.Enumerable.<ExceptIterator>d__99`1.MoveNext()
   at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)

GenerateDiff()修改为:

private void GenerateDiff()
{
    var file1Lines = File.ReadLines(firstFile).ToList();
    var file2Lines = File.ReadLines(secondFile).ToList();

    inFirstNotInSecond = file1Lines.Except(file2Lines);
    inSecondNotInFirst = file2Lines.Except(file1Lines);
}

我无法重现异常。

有趣的是,这不起作用:

private void GenerateDiff()
{
    var file1Lines = File.ReadLines(firstFile);
    var file2Lines = File.ReadLines(secondFile);

    inFirstNotInSecond = file1Lines.Except(file2Lines).ToList();
    inSecondNotInFirst = file2Lines.Except(file1Lines).ToList();
}

我在这里使用此类diff的实例。在任何地方都没有usingDispose。没有任务或线程。

if (diff.InSecondNotInFirst.Any(s => !s.Contains("bxsr")))

有人可以解释根本原因吗?谢谢。

(我们的猜测是,这是因为IEnumerable<>实现了延迟加载,垃圾收集器在我想要访问InFirstNotInSecondInSecondNotInFirst之前关闭了阅读器。但是使用{{1}在某些机器上仍然没有例外。)

3 个答案:

答案 0 :(得分:4)

使用source code,我们看到File.ReadLines返回ReadLinesIterator

here你可以看到它们在枚举后Dispose。

这意味着File.ReadLines的枚举只能发生一次。 最好使用File.ReadAllLines,它将首先枚举并返回一个具体的数组。

答案 1 :(得分:1)

立即调用ToList(),您可以强制ReadLines立即执行并阅读整个文件。继续,你现在正在处理List<string>而不是IENumerable

第二种方法不起作用的原因是,您再次创建了两个IENumerables,这些Except仅在ToList()方法时被评估(并且同时重复)调用。 Except后面的IENumerable只会将您从Except方法获得的List<string>转换为ObjectDisposedException

至于为什么你得到一个TextReader我猜想IENumeration会在被枚举之后被处理掉,因为你试图经过同一个ToList()两次Except如果它放在{{1}}的末尾

,它将无法帮助

答案 2 :(得分:1)

这可能需要大量内存,因为将加载两个文件:

private void GenerateDiff()
{
    var file1Lines = File.ReadLines(firstFile).ToList();
    var file2Lines = File.ReadLines(secondFile).ToList();

    inFirstNotInSecond = file1Lines.Except(file2Lines);
    inSecondNotInFirst = file2Lines.Except(file1Lines);
}

如果您使用ReadAllLines,则同样如此。

性能较差的解决方案,但内存效率更高:

void GenerateDiff()
{
     inFirstNotInSecond = File.ReadLines(firstFile).Except(File.ReadLines(secondFile)).ToList();
     inSecondNotInFirst = File.ReadLines(secondFile).Except(File.ReadLines(firstFile)).ToList();
}

由于您正在访问相同的文件,因此可能会对其进行缓存,因此缺点应该可以忽略不计。

P.S。:我的回答是假设Except()延迟执行