我无法从我的程序的更高版本反序列化序列化产生的中等复杂对象。我得到例外:
System.Runtime.Serialization.SerializationException was unhandled
Message=The ObjectManager found an invalid number of fixups. This usually indicates a problem in the Formatter.
Source=mscorlib
StackTrace:
at System.Runtime.Serialization.ObjectManager.DoFixups()
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)
at Microsoft.Samples.TestV1.Main(String[] args) in c:\Users\andrew\Documents\Visual Studio 2013\Projects\vts\CS\V1 Application\TestV1Part2\TestV1Part2.cs:line 29
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
...
这与在旧版本的更高版本中尝试反序列化已更改的对象(添加的成员)有关。但是,微软声称它应该可以工作,因为VTS。请参阅:https://msdn.microsoft.com/en-us/library/ms229752(v=vs.110).aspx
它们提供了一个未经修改的示例,确实允许您使用旧版本反序列化更新的类。看到: https://msdn.microsoft.com/en-us/library/7a6c3wzt(v=vs.110).aspx
但是,正如这里暗示的那样:Deserialization backwards compatibility带有评论,
kareph, what is the real type of Zoo ? I remember some types (arrays) just didn't work right.
- 使事情不相容并不需要太多。我使用了Microsoft的VTS示例(如上所列)并将以下内容添加到" Person"下的V2 ApplicationCS示例中。类:
[OptionalField(VersionAdded = 2)]
private List<HealthData> _healthDataList;
public List<HealthData> HealthDataList
{
get { return _healthDataList; }
set { _healthDataList = value; }
}
HealthData只定义为:
[Serializable]
public class HealthData
{
#region Fields
private int _weight;
private int _height;
#endregion
#region Properties
public int Weight
{
get { return _weight; }
set { _weight = value; }
}
public int Height
{
get { return _height; }
set { _height = value; }
}
#endregion
}
这足以得到可怕的异常&#34; ...无效的修正数......&#34;。
奇怪的是,如果我只添加一个整体列表,一切都很好。我的问题是:
我的实际类结构比Microsoft示例复杂得多,但我确实有阵列和列表&lt;&gt;所以这是首先要考虑的好事。但可能还有其他的&#34;陷阱&#34;简单的微软例子没有。
非常感谢任何想法或帮助。
戴夫
答案 0 :(得分:2)
我最近遇到了类似的问题,我找不到关于这些“陷阱”的提及
反序列化失败的原因如下:
ObjectManager具有不同的逻辑来解析数组以及引用和值类型的依赖关系。
您添加了一个新的引用类型数组,它在程序集中不存在(您将其标记为第二个版本)
当ObjectManager尝试解析依赖关系时,它会构建图形
当它看到数组时,它无法立即修复它,因此它会创建一个虚拟引用,然后再修复该数组
由于此类型不在程序集中,因此无法解析依赖项。 出于某种原因,它不会从修复的元素列表中删除该数组,最后它会抛出异常“IncorrectNumberOfFixups”
出于某种原因,它仅针对新引用类型的数组抛出异常,因此如果您使用新结构而不是类的集合,一切都将正常工作
控制序列化过程有三种方法,具体取决于您如何更改旧代码:
使用序列化活页夹
使用Serizaliation Surrogates
使用ISerialization。适用于您无法更改旧代码和旧代码的情况,您尚未进行受控序列化过程
您可以使用简单的解决方案,但这并不好。 实现ISerializable并将您的新类数组编译为类数组,但仅作为数组序列,在数组之外
因此它将适用于旧版本的程序
有用的说明:
此外,您可以通过使用第二种方法来解决这个问题,只需使用结构数组或使用Dictionary,因此作为Dictionary中的每个元素,它就是结构
您可以做的一个例子: 我不推荐使用此方法,但使用此方法,您将能够保持向后兼容性
[Serializable]
class NewItem
{
public string Name;
}
[Serializable]
class Item : ISerializable
{
[OptionalField]
private List<NewItem> _newItems;
public List<NewItem> NewItems
{
get { return _newItems; }
set { _newItems = value; }
}
public Item()
{
}
protected Item(SerializationInfo info, StreamingContext context)
{
var newItemsSize = (int)info.GetValue("_newItemsSize", typeof(int));
_newItems = new List<NewItem>(newItemsSize);
for (int i = 0; i < newItemsSize; i++)
{
var item = (NewItem)info.GetValue($"_newItem{i}", typeof(NewItem));
_newItems.Add(item);
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("_newItemsSize", _newItems.Count, typeof(int));
for (int i = 0; i < _newItems.Count; i++)
info.AddValue($"_newItem{i}", _newItems[i], typeof(NewItem));
}
}