序列化对象消失(BinaryFormatter)

背景

我有一个对象需要序列化才能转移到高性能计算集群供以后使用

以前,我已经为我的对象使用了开箱即用的二进制格式化程序,它代表了一个统计形状模型,并且都很愉快地工作

我的对象变得更加复杂,我决定通过实现ISerializable来自定义序列化过程。 我继续支持以先前格式存储的数据

问题

我的问题是,一个特定值似乎成功序列化,但在尝试反序列化时始终具有null值。 (没有错误,只是一个非常不愉快,无用的空值)

当我在序列化时断开时,我可以通过检查SerializationInfo并且它有值(它没什么特别的,但是会在下面发布它的代码)看到该对象被添加到SerializationInfo中。

正在调用序列化构造函数(我也在那里设置了一个断点),但是当我检查构造函数的SerializationInfo对象时,它没有数据(它有一个条目,只有没有数据)

更新 – 在这里下载控制台应用程序。 谢谢你的期待

或者,看看这里的代码:

代码

导致问题的类:( PointProfiles属性是违规对象)

[Serializable] public class TrainingSet : ITrainingSet, ISerializable { public Dictionary<Tuple, IPointTrainingSet> PointProfiles { get; set; } public PrincipalComponentAnalysis PointPCA { get; set; } public double[] AlignedMean { get; set; } public List<Tuple> Transforms { get; set; } public string[] FileNames { get; set; } private static Lazy formatter = new Lazy(); public static ITrainingSet Load(Guid modelId) { ModelSample s = DataProxy.AsQueryable().Where(m => m.ModelId == modelId).SingleOrDefault(); if (s == null) return null; byte[] raw = s.Samples.ToArray(); using (MemoryStream ms = new MemoryStream(raw)) return (ITrainingSet)formatter.Value.Deserialize(ms); } void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("pca", PointPCA); info.AddValue("tp1", PointProfiles.Select(pp => pp.Key.Item1).ToArray()); info.AddValue("tp2", PointProfiles.Select(pp => pp.Key.Item2).ToArray()); var x = PointProfiles.Select(pp => (ProfileModel)pp.Value).ToArray(); info.AddValue("ipts", x, typeof(ProfileModel[])); info.AddValue("am", AlignedMean); info.AddValue("tname", Transforms.Select(t => t.Item1).ToArray()); info.AddValue("tval", Transforms.Select(t => t.Item2).ToArray()); info.AddValue("fnames", FileNames); info.AddValue("version", 1); // nb } public TrainingSet(SerializationInfo info, StreamingContext context) { int version = 0; foreach(SerializationEntry s in info) { if(s.Name == "version") version = (int)s.Value; } switch(version) { case 0: // old (default binary formatter) PointPCA = info.GetValue("k__BackingField", typeof(PrincipalComponentAnalysis)) as PrincipalComponentAnalysis; PointProfiles = info.GetValue("k__BackingField", typeof(Dictionary<Tuple, IPointTrainingSet>)) as Dictionary<Tuple, IPointTrainingSet>; AlignedMean = info.GetValue("k__BackingField", typeof(double[])) as double[]; Transforms = info.GetValue("k__BackingField", typeof(List<Tuple>)) as List<Tuple>; FileNames = info.GetValue("k__BackingField", typeof(string[])) as string[]; //stats.PointPCA = pointPCA; //stats.PointProfiles = pointProfiles; //stats.AlignedMean = alignedMean; //stats.Transforms = transforms; //stats.FileNames = fileNames; break; case 1: FileNames = info.GetValue("fnames", typeof(string[])) as string[]; var t = info.GetValue("tval", typeof(ITransform[])) as ITransform[]; var tn = info.GetValue("tname", typeof(string[])) as string[]; Transforms = new List<Tuple>(); for(int i = 0;i < tn.Length;i++) Transforms.Add(new Tuple(tn[i], t[i])); AlignedMean = info.GetValue("am", typeof(double[])) as double[]; PointPCA = info.GetValue("pca", typeof(PrincipalComponentAnalysis)) as PrincipalComponentAnalysis; var ipts = info.GetValue("ipts", typeof(ProfileModel[])); foreach (var x in info) { int a = 0; a++; // break point here, info has an entry for key "ipts", but it's null (or rather an array of the correct length, and each element of the array is null) } var xxx = ipts as IPointTrainingSet[]; var i2 = info.GetValue("tp2", typeof(int[])) as int[]; var i1 = info.GetValue("tp1", typeof(int[])) as int[]; PointProfiles = new Dictionary<Tuple, IPointTrainingSet>(); for (int i = 0; i < i1.Length; i++) PointProfiles.Add(new Tuple(i1[i], i2[i]), xxx[i]); break; default: throw new NotImplementedException("TrainingSet version " + version + " is not supported"); } } public TrainingSet() { } } 

Profile类(也可序列化,这是ProfileModel的基类,下面列出)

  [Serializable] public class Profile : ISerializable, IProfile { public double Angle { get; private set; } public int PointIndex { get; private set; } public int Level { get; set; } public double[,] G { get; private set; } public virtual double[,] GBar { get { throw new InvalidOperationException(); } } public virtual int Width { get { return G.Length; } } public Profile(int level, int pointIndex, double angle, double[,] G) { this.G = G; PointIndex = pointIndex; Level = level; Angle = angle; } // deserialization public Profile(SerializationInfo info, StreamingContext context) { PointIndex = info.GetInt32("p"); Angle = info.GetDouble("a"); G = (double[,])info.GetValue("g", typeof(double[,])); Level = info.GetInt32("l"); //_pca = new Lazy(Pca); } // serialization public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("p", PointIndex); info.AddValue("a", Angle); info.AddValue("g", G); info.AddValue("l", Level); } } 

和(最后)ProfileModel类:

 [Serializable] public class ProfileModel : Profile, ISerializable, IPointTrainingSet { public IProfile MeanProfile { get; private set; } private ProfileModel(int level, int PointIndex, IProfile[] profiles) : base(level, PointIndex, 0, null) { double[,] m = Matrix.Create(profiles.Length, profiles[0].G.Columns(), 0); int idx = 0; foreach (var pg in profiles.Select(p => pGGetRow(0))) m.SetRow(idx++, pg); Profile meanProfile = new Profile(level, PointIndex, 0, m.Mean().ToMatrix()); MeanProfile = meanProfile; } // deserialization public ProfileModel(SerializationInfo info, StreamingContext context) : base(info, context) { var ps = info.GetValue("mp", typeof(Profile)); MeanProfile = (IProfile)ps; } // serialization public new void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("mp", MeanProfile, typeof(Profile)); base.GetObjectData(info, context); } public override double[,] GBar { get { return MeanProfile.G; } } public override int Width { get { return GBar.Columns(); } } } 

如果你能发现任何可能导致这种情况发生的错误,我会非常感激:)

arrays首先反序列化,然后执行内部解除旋转。 当循环遍历ProfileModel数组时,它的内容尚未被去动化。

您可以通过实现IDeserializationCallback(或通过将OnDeserilized属性分配给应在deserilization完成时调用的方法)来解决此问题。 在反序列化整个对象图之后调用OnDeserialzation方法。

您需要将数组存储在私有字段中:

 private int []i1; private int []i2; private ProfileModel [] ipts; 

在derserialization下执行以下操作:

 ipts = info.GetValue("ipts", typeof(ProfileModel[])); i2 = info.GetValue("tp2", typeof(int[])) as int[]; i1 = info.GetValue("tp1", typeof(int[])) as int[]; 

并实现IDeserializationCallback:

 public void OnDerserilization(object sender) { PointProfiles = new Dictionary, IPointTrainingSet>(); for (int i = 0; i < i1.Length; i++) PointProfiles.Add(new Tuple(i1[i], i2[i]), ipts[i]); } 

通过让.NET处理List和Dictionary序列化而不是尝试手动执行它,我能够使这个工作:

 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("pca", PointPCA); info.AddValue("pps", PointProfiles); info.AddValue("am", AlignedMean); info.AddValue("transforms", Transforms); info.AddValue("fnames", FileNames); } public TrainingSet(SerializationInfo info, StreamingContext context) { PointPCA = info.GetValue("pca", typeof(PrincipalComponentAnalysis)) as PrincipalComponentAnalysis; Transforms = (List>)info.GetValue("transforms", typeof(List>)); AlignedMean = info.GetValue("am", typeof(double[])) as double[]; PointProfiles = (Dictionary, IPointTrainingSet>)info.GetValue("pps", typeof(Dictionary, IPointTrainingSet>)); FileNames = info.GetValue("fnames", typeof(string[])) as string[]; } 

你有一个非常复杂的对象图。 我尝试打破ProfileProfileModel的构造函数并得到一些奇怪的结果,但这个简单的版本似乎工作。