File.ReadLines 啥时候释放资源

Posted

技术标签:

【中文标题】File.ReadLines 啥时候释放资源【英文标题】:When does File.ReadLines free resourcesFile.ReadLines 什么时候释放资源 【发布时间】:2011-03-23 16:44:30 【问题描述】:

在使用 C# 处理文件时,我习惯于考虑释放相关资源。通常这是一个 using 语句,除非它是一个单一的便捷方法 比如 File.ReadAllLines,它将为我打开和关闭文件。

.Net 4.0 引入了便捷方法 File.ReadLines。这将返回一个 IEnumerable,并被认为是一种更有效的文件处理方式——它避免了将整个文件存储在内存中。为此,我假设枚举器中有一些延迟执行逻辑。

显然,由于此方法返回的是 IEnumerable,而不是 IDisposable,因此我无法接受 using 语句的直觉反应。

我的问题是: 考虑到这一点,使用这种方法释放资源是否有任何陷阱?

调用这个方法是否意味着关联文件锁的释放是不确定的?

【问题讨论】:

【参考方案1】:

IEnumerable 不从 IDisposable 继承,因为通常,实现它的类只为您提供可枚举的承诺,它实际上还没有做任何需要处置的事情。

但是,当您枚举它时,您首先通过调用IEnumerable.GetEnumerator 方法检索IEnumerator,通常,您返回的底层对象确实实现IDisposable

foreach的实现方式类似这样:

var enumerator = enumerable.GetEnumerator();
try

    // enumerate

finally

    IDisposable disposable = enumerator as IDisposable;
    if (disposable != null)
        disposable.Dispose();

这样,如果对象确实实现了IDisposable,它将被丢弃。对于File.ReadLines,文件在您开始枚举之前不会真正打开,因此您从File.ReadLines 获得的对象不需要处理,但您获得的枚举器需要处理。

正如 cmets 所指出的,IEnumerator 不继承自 IDisposable,尽管许多典型实现确实如此,而通用 IEnumerator<T> 确实继承 IDisposable

【讨论】:

实际上,IEnumerator 并没有实现 IDisposable。但是 IEnumerator 的许多实现确实实现了 IDisposable,foreach 循环和 LINQ 扩展方法都执行as 强制转换以查看枚举器是否实现了 IDisposable,如果是,它们调用 Dispose。 更正:非泛型 IEnumerator 不实现 IDisposable,但泛型 (IEnumerator<T>) 可以。 啊,你是对的。啊,愚蠢的错误,让我编辑答案。【参考方案2】:

+1 表示 Lasse 的回答。

特别是对于枚举器调用.MoveNext()File.ReadLines,内部TextReader 将在遇到EOF 或发生故障时被释放。

private bool MoveNext()

    bool flag;
    try
    
        switch (this.<>1__state)
        
            case 0:
                this.<>1__state = -1;
                this.<>7__wrap2 = this.reader;
                this.<>1__state = 1;
                this.<line>5__1 = null;
                goto Label_005C;

            case 2:
                this.<>1__state = 1;
                goto Label_005C;

            default:
                goto Label_0078;
        
    Label_003E:
        this.<>2__current = this.<line>5__1;
        this.<>1__state = 2;
        return true;
    Label_005C:
        if ((this.<line>5__1 = this.reader.ReadLine()) != null)
        
            goto Label_003E;
        
        this.<>m__Finally3(); // Disposal at end of file.
    Label_0078:
        flag = false;
    
    fault
    
        this.System.IDisposable.Dispose(); // Disposal due to fault.
    
    return flag;

【讨论】:

【参考方案3】:

只是为了更新:

在.net 5 中,它返回的IEnumerable 确实实现了IDisposable,您可能需要在转换后调用Dispose。但如果您阅读到文件末尾,它会自行处理。

【讨论】:

以上是关于File.ReadLines 啥时候释放资源的主要内容,如果未能解决你的问题,请参考以下文章

java 啥资源需要手动释放

java中一个线程啥时候释放资源啊?问题补充中是我情况的说明.

c#啥时候有必要用using(代码段)?

悲观锁和乐观锁,啥情况

C#using()是啥意思

autorelease 对象啥时候释放?