IDisposable在构造函数链中

时间:2019-04-12 00:28:08

标签: c# .net idisposable

我有以下两个构造函数:

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字段。我可以在每个构造函数中复制逻辑,但这显然不是一个好的解决方案。

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

2 个答案:

答案 0 :(得分:4)

我不太确定是什么阻止您在采用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
}

如果是因为您想让Stream构造函数的调用者保持FileStream有效,则可以添加第三个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();
        }
    }
}

答案 1 :(得分:4)

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

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

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

内部都使用参数Init调用相同的leaveOpen方法,第一个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();
        }
    }
}