我有一些准备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
需要保持打开状态?
我可以想到解决这个问题的一些非常不方便的方法,但是我想知道它为什么不能按我想要的方式工作,以及是否有我的东西我可以做到这一点。感谢任何建议,谢谢!
答案 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);
}