【发布时间】:2016-05-23 13:40:52
【问题描述】:
我有一个系统可以使用不同的序列化器(BinaryFormatter、XmlSerializer、Json.Net)将数据写入文件。我已将它们包装在我自己的 IStreamSerializer 接口中,并希望确保它们在我的应用程序上下文中的行为相同。这是我的一种测试方法:
[Test]
public void JsonSerializer_RoundtripsMap_Successfully()
{
Map map = new Map(2, 4, TileType.Grass);
IStreamSerializer serializer = new JsonSerializer(); // Json.Net
using (var ms = new MemoryStream())
{
serializer.Serialize(ms, map);
ms.Position = 0;
Map loaded = serializer.Deserialize<Map>(ms);
// Asserts...
}
}
我创建了一个MemoryStream,将它序列化并尝试读回它,断言返回的对象是否相同。这适用于 BinaryFormatter 和 XmlSerializer。但是,当我将流位置重置为零时,Json.Net 会引发异常:
System.ObjectDisposedException : The object was used after being disposed.
这是我的 JsonSerializer.Serialize 方法:
public void Serialize(Stream stream, object data)
{
var serializer = new Newtonsoft.Json.JsonSerializer();
using (var textWriter = new StreamWriter(stream))
using (var jsonWriter = new JsonTextWriter(textWriter))
{
serializer.Serialize(jsonWriter, data);
}
}
我知道 Dispose 在 using 语句的末尾被调用,这就是我返回测试类时无法设置流位置的原因方法。
我怎样才能使它正常工作?我已经尝试了很多可能的解决方案,但它们要么最终损坏了序列化文件,要么抛出了诸如 无法读取流之类的错误>.
这会引发 JsonReaderException 并破坏物理写入的文件,但它确实通过了测试:
public void Serialize(Stream stream, object data)
{
var serializer = new Newtonsoft.Json.JsonSerializer();
var textWriter = new StreamWriter(stream);
var jsonWriter = new JsonTextWriter(textWriter);
serializer.Serialize(jsonWriter, data);
}
同样,BinaryFormatter 和 XmlSerializer 在我的测试用例中都能正常工作。当我调用 formatter.Serialize 时,它们似乎没有处理流,但如果我以同样的方式尝试,Json.Net 就不再写入正确的数据了。 p>
注意:我的框架只能使用自定义版本的 .Net,类似于 v3.5。
【问题讨论】:
-
您需要在使用完
JSONTextWriter并处理它之后,将StreamWriter处理掉。AFTER此外,如果您没有处理流,则预计文件会“损坏”。 dispose 方法通常还会将内存中剩余的内容刷新到文件中 -
StreamWriter将获得所有权并关闭Dispose上的流。bool leaveOpen有一个构造函数重载。在这里查看更多信息:msdn.microsoft.com/en-us/library/gg712853(v=vs.110).aspx -
using 语句已经做到了,对吧?但是一旦一切都关闭了,我就不能再做 stream.Position = 0 了,这就是问题所在。但我还需要关闭流以使 Json.Net 正常工作。也许这是他们的序列化程序中的一个错误。
-
StreamWriter将在您重置Position之前关闭您的MemoryStream。StreamWriter可以在离开您的Serialize方法时被释放,并将关闭您的MemoryStream。这可能会有所帮助:var textWriter = new StreamWriter(stream, Encoding.UTF8, 512, true)) -
leaveOpen 构造函数重载听起来和我想要的完全一样。太糟糕了,我使用的是类似于 .Net 2.0 的 .Net 版本,具有 3.5(Unity Mono)的某些功能。那个版本没有说过载。
标签: c# serialization dispose memorystream