【问题标题】:Serialized objects disappearing (BinaryFormatter)序列化对象消失(BinaryFormatter)
【发布时间】:2013-04-03 13:43:39
【问题描述】:

背景

我有一个需要序列化的对象,以便传输到高性能计算集群供以后使用

以前,我为我的对象使用了开箱即用的二进制格式化程序,它代表了一个统计形状模型,并且一切正常

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

问题

我的问题是一个特定的值似乎可以成功序列化,但是当我尝试反序列化时总是有一个 null 值。 (没有错误,只是一个非常不愉快、无用的 null)

当我在序列化点中断时,我可以通过检查 SerializationInfo 看到对象已添加到 SerializationInfo 中,并且它具有值(这没什么花哨的,但会在下面发布它的代码)

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

更新 - 下载控制台应用程序here。感谢观看

或者,看这里的代码:

守则

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

   [Serializable]
    public class TrainingSet : ITrainingSet, ISerializable
    {
        public Dictionary<Tuple<int, int>, IPointTrainingSet> PointProfiles { get; set; }

        public PrincipalComponentAnalysis PointPCA { get; set; }

        public double[] AlignedMean { get; set; }

        public List<Tuple<string, ITransform>> Transforms { get; set; }

        public string[] FileNames { get; set; }

        private static Lazy<BinaryFormatter> formatter = new Lazy<BinaryFormatter>();

        public static ITrainingSet Load(Guid modelId)
        {
            ModelSample s = DataProxy<ModelSample>.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("<PointPCA>k__BackingField", typeof(PrincipalComponentAnalysis)) as PrincipalComponentAnalysis;
                    PointProfiles = info.GetValue("<PointProfiles>k__BackingField", typeof(Dictionary<Tuple<int, int>, IPointTrainingSet>)) as Dictionary<Tuple<int, int>, IPointTrainingSet>;
                    AlignedMean = info.GetValue("<AlignedMean>k__BackingField", typeof(double[])) as double[];
                    Transforms = info.GetValue("<Transforms>k__BackingField", typeof(List<Tuple<string, ITransform>>)) as List<Tuple<string, ITransform>>;
                    FileNames = info.GetValue("<FileNames>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<string, ITransform>>();
                    for(int i = 0;i < tn.Length;i++)
                        Transforms.Add(new Tuple<string,ITransform>(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<int, int>, IPointTrainingSet>();
                    for (int i = 0; i < i1.Length; i++)
                        PointProfiles.Add(new Tuple<int, int>(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<PrincipalComponentAnalysis>(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<double>(profiles.Length, profiles[0].G.Columns(), 0);

        int idx = 0;
        foreach (var pg in profiles.Select(p => p.G.GetRow(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();
    } }
}

如果您能发现我做错了什么可能导致这种情况发生,我将非常感激:)

【问题讨论】:

  • @Rohrbs - 感谢您查看 :) 我确实想知道 - 这就是为什么元组和字典以定制的、单独的方式序列化的原因(参见名为“tp1”和“tp2”的键- “ipts”是字典的第三部分)
  • 很抱歉,仔细看了之后,没有什么东西在我身上跳出来。也许这里有演员pp =&gt; (int)pp.Key.Item1?哪些值返回 null? tp1、tp2 还是 ipts?三个?
  • 没问题,感谢您的关注。只是 ipts 为空。

标签: c# .net serialization binaryformatter


【解决方案1】:

数组首先反序列化,然后执行内部反序列化。在遍历 ProfileModel 数组时,它的内容还没有被反序列化。

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

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

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

在反序列化下执行以下操作:

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<Tuple<int, int>, IPointTrainingSet>();

  for (int i = 0; i < i1.Length; i++)
     PointProfiles.Add(new Tuple<int, int>(i1[i], i2[i]), ipts[i]);
}

【讨论】:

    【解决方案2】:

    我能够通过让 .NET 处理列表和字典序列化而不是尝试手动完成它来使其工作:

    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<Tuple<string, ITransform>>)info.GetValue("transforms", typeof(List<Tuple<string, ITransform>>));
        AlignedMean = info.GetValue("am", typeof(double[])) as double[];
        PointProfiles = (Dictionary<Tuple<int, int>, IPointTrainingSet>)info.GetValue("pps", typeof(Dictionary<Tuple<int, int>, IPointTrainingSet>));
        FileNames = info.GetValue("fnames", typeof(string[])) as string[];
    }
    

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

    【讨论】:

    • 非常感谢您查看它,但我已经让它像那样工作了 - 我想自己做,因为 Mono 不能很好地处理这种方式(我在microsoft环境中序列化,在linux环境下反序列化)。
    猜你喜欢
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多