为什么StreamWriter需要打开才能访问我的MemoryStream?

时间:2015-11-11 20:48:13

标签: c# idisposable streamwriter memorystream

我有一些准备MemoryStream的测试代码,最终会被对象读取。以下是我想要编写它的方式:

        var manager = new LeaderboardImportManager(leaderboard);
        var columnNames = manager.ColumnNames;

        var stream = new MemoryStream();
        using (var writer = new StreamWriter(stream))
        {
            writer.WriteLine(string.Join(",", columnNames));
            foreach (var user in users)
            {
                var row = leaderboard.Metrics.Select(m => Faker.RandomNumber.Next().ToString()).ToList();
                row.Insert(0, user.UserName);
                writer.WriteLine(string.Join(",", row));
            }

            writer.Flush();
            stream.Position = 0;
        }

        return stream;

但是当我这样做时,我的流对象变得不可读并且我的测试失败了,所以我必须这样做:

        var manager = new LeaderboardImportManager(leaderboard);
        var columnNames = manager.ColumnNames;

        var stream = new MemoryStream();
        var writer = new StreamWriter(stream);

        writer.WriteLine(string.Join(",", columnNames));
        foreach (var user in users)
        {
            var row = leaderboard.Metrics.Select(m => Faker.RandomNumber.Next().ToString()).ToList();
            row.Insert(0, user.UserName);
            writer.WriteLine(string.Join(",", row));
        }

        writer.Flush();
        stream.Position = 0;
        return stream;

这当然阻止我处理我的StreamWriter对象,据我所知,它应该被处置掉。

如果我已将其内容刷新到StreamWriter对象,为什么MemoryStream需要保持打开状态?

我可以想到解决这个问题的一些非常不方便的方法,但是我想知道它为什么不能按我想要的方式工作,以及是否有我的东西我可以做到这一点。感谢任何建议,谢谢!

4 个答案:

答案 0 :(得分:3)

默认情况下,StreamWriter"拥有"它被传递的流将在处理时关闭它。使用具有leaveOpen boolean parameter的构造函数。将其设置为true以避免在第一个示例中放置编写器时关闭基础Stream

答案 1 :(得分:2)

在退出运算符块using之前,

Dispose运算符调用对象上的{ }方法。

在处置时,StreamWriter也会处置基础Stream

这意味着您的Stream在返回之前是一个无效的对象。

仅对在当前范围内创建和销毁的对象应用using语句(至少不返回它们)。

  

为什么StreamWriter需要保持打开状态才能刷新它   内容已经到了MemoryStream对象?

正如@mikez所提到的,默认情况下创建StreamWriter“拥有”基础流,但您可以通过在构造函数中添加leaveOpen = true来避免此行为。

new StreamWriter(stream = s, encoding = Encoding.UTF8, bufferSize = 128, leaveOpen = true)

答案 2 :(得分:2)

StreamWriter会自动关闭Stream,如果你不告诉它的话。像这样创建它而不是打开Stream

using (var writer = new StreamWriter(stream, System.Text.Encoding.UTF8, 1024, true))

或者,如果您不想传递额外的参数,请使用GetBuffer访问MemoryStream的内部缓冲区。避免使用ToArray,因为这会创建数据副本,具体取决于您的方案可能效率低下。

答案 3 :(得分:0)

其他答案表明我应该使用具有leaveOpen参数的构造函数并将其设置为true,但我不喜欢这个,因为构造函数还需要bufferSize参数。

然而,我意识到我可以轻松地逃脱这个:

        // new method body, returns byte array

        var stream = new MemoryStream();
        using (var writer = new StreamWriter(stream))
        {
            writer.WriteLine(string.Join(",", columnNames));
            foreach (var user in users)
            {
                var row = leaderboard.Metrics.Select(m => Faker.RandomNumber.Next().ToString()).ToList();
                row.Insert(0, user.UserName);
                writer.WriteLine(string.Join(",", row));
            }

            writer.Flush();
            stream.Position = 0;
        }

        return stream.ToArray();

        // consumer opens a new stream using the bytes

        using (var stream = new MemoryStream(this.GetCSVStream(leaderboard, users)))
        {
            mockFile.Setup(f => f.InputStream).Returns(stream);
            this.service.UpdateEntries(update.ID, mockFile.Object);
        }