构造函数链中的 IDisposable

IDisposable within Constructor Chain

我有以下两个构造函数:

public Source(FileStream fileStream) {
    // Stuff
}

public Source(String fileName) : this(new FileStream(fileName, FileMode.Open)) {
    // Nothing, the other constructor does the work
}

第二个构造函数的问题很明显,正在创建和使用 FileStream,但没有释放。因为它在构造函数链中,所以 using 块是不可能的。我无法将 new FileStream() 移动到构造函数的主体中,因为虽然它会在 using 块中,但无法调用其他构造函数的逻辑。我无法提取该逻辑,因为它修改了 readonly 字段。我可以在每个构造函数中复制逻辑,但这显然不是一个好的解决方案。

我真的更愿意保留第二个构造函数提供的语法糖。我怎样才能最好地做到这一点?或者这只是个坏主意?

我不太确定是什么阻止你在采用 FileStream:

的构造函数中处理它
public Source(FileStream fileStream) {
    try
    {
        // Stuff
    }
    finally
    {
        fileStream.Dispose();
    }
}

public Source(String fileName) : this(new FileStream(fileName, FileMode.Open)) {
    // Nothing, the other constructor does the work
}

如果是因为你想让 StreamFileStream 构造函数的调用者保持活动状态,你可以添加第三个 private 构造函数:

public Source(FileStream fileStream): this(fileStream, disposeStream: false) {
    // Nothing, the other constructor does the work
}

public Source(String fileName) : this(new FileStream(fileName, FileMode.Open), disposeStream: true) {
    // Nothing, the other constructor does the work
}

private Source(FileStream fileStream, bool disposeStream) {
    try
    {
        // Stuff
    }
    finally
    {
        if (disposeStream)
        {
            fileStream.Dispose();
        }
    }
}

看看 StreamReader 实现,它有两种类型的 ctors:

public StreamReader(Stream stream)
      : this(stream, true)
    {
    }

public StreamReader(string path)
      : this(path, true)
    {
    }

在内部,它们都使用参数 leaveOpen 调用相同的 Init 方法,第一个 ctor 设置为 true,第二个 ctor 设置为 false并基于此参数 Stream 得到(或不)处置。

所以你可以这样做:

public class Source : IDisposable
{
    private readonly Stream _stream;
    private readonly bool _leaveOpen;

    private Source(Stream stream, bool leaveOpen)
    {
        _stream = stream;
        _leaveOpen = leaveOpen;
    }

    public Source(FileStream fileStream) : this(fileStream, true)
    {

    }

    public Source(string fileName) : this(new FileStream(fileName, FileMode.Open), false)
    {

    }

    public void Dispose()
    {
        if (!_leaveOpen)
        {
            _stream?.Dispose();
        }
    }
}