使用可选字段的反序列化错误

本文关键字:反序列化 错误 字段 | 更新日期: 2023-09-27 18:36:27

向类添加新的可选字段后,该类的以前序列化的实例不再可反序列化。

假设我使用 BinaryFormatter 保存了一些 MyClass 实例:

[Serializable]
public class MyClass
{
    public MyType A;
}

之后,MyClass的第二次修订版:

[Serializable]
public class MyClass
{
    public MyType A;
    [OptionalField(VersionAdded = 2)]
    public MyType NewField;
}

现在,较旧的对象不再可反序列化。尝试反序列化它们时获得的堆栈跟踪如下(配置文件为 .NET 4.0):

System.ArgumentNullException: Value cannot be null.    
Parameter name: type    
   at System.Reflection.Assembly.GetAssembly(Type type)    
   at System.Runtime.Serialization.Formatters.Binary.BinaryConverter.GetParserBinaryTypeInfo(Type type, Object& typeInformation)    
   at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, Type objectType, String[] memberNames, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo)    
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMap(BinaryObjectWithMap record)    
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()    
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)    
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)    
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, IMethodCallMessage methodCallMessage)    
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck)

我在互联网或类似的堆栈跟踪上找不到此堆栈跟踪。请注意,使用Mono运行软件可以读取相同的文件;-)。因此,我认为问题可能与.NET错误有关。

使用可选字段的反序列化错误

假设我有以下类类型。

[Serializable]
public class MyClass
{
    public MyType A;
}
[Serializable]
public class MyType
{
    public string Name { get; set; }
}

让我们将 MyClass 的实例序列化为一个文件。

using (var stream = new FileStream(@"c:'temp'test.dat", FileMode.Create, FileAccess.Write))
{
    var formatter = new BinaryFormatter();
    formatter.Serialize(stream, new MyClass { A = new MyType { Name = "Christophe" } });
}

现在我们将其反序列化回 MyClass 的实例。

using (var stream = new FileStream(@"c:'temp'test.dat", FileMode.Open, FileAccess.Read))
{
    var formatter = new BinaryFormatter();
    var myInstance = (MyClass) formatter.Deserialize(stream);
}

没关系。一切正常。让我们向 MyClass 类型添加一个新字段。我建议你改用属性。

[Serializable]
public class MyClass
{
    public MyType A;
    [OptionalField]
    public MyType B;
}

反序列化仍然工作正常。在我的例子中,B的缺失数据被忽略,它被设置为null。