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

Why does StreamWriter need to be open to access my 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 对象,据我所知,它绝对应该被处理。

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

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

using 运算符在退出运算符块 { }.

之前调用对象的 Dispose 方法

在处置时,StreamWriter 也处置标的 Stream

这意味着您的 Stream 在得到 returned 之前是一个无效的对象。

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

Why does the StreamWriter need to remain open if I've flushed its contents to the MemoryStream object already?

如@mikez 所述,默认情况下创建 StreamWriter "owns" 底层流,但您可以通过在构造函数中添加 leaveOpen = true 来避免此行为。

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

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

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

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

或者,如果您不想传递额外的参数,请使用 GetBuffer 访问 MemoryStream 的内部缓冲区。避免 ToArray,因为这会创建数据副本,并且根据您的情况可能效率低下。

其他答案表明我应该使用具有 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);
        }