2013-04-03 49 views
3

背景序列化對象消失(BinaryFormatter的)

我有一個對象,我需要爲了轉移至高性能計算集羣用於以後使用

此前序列化,我使用的出我的對象代表一個統計形狀模型,並且所有人都愉快地工作了。我的對象變得更加複雜了,我決定通過實現ISerializable定製序列化過程。我繼續支持存儲在先前格式的數據

的問題

我的問題是一個具體值似乎成功序列化,但始終都是空值,當我試圖反序列化。 (沒有錯誤,只是一個非常不愉快的,無用的null)

當我在序列化的時候斷開,我可以看到對象被添加到SerializationInfo ok通過檢查SerializationInfo並且它有值(它是沒有什麼奇特的,但會發佈下面的代碼)

序列化構造函數正在調用(我也放了一個斷點),但是當我檢查構造函數的SerializationInfo對象時,它沒有數據(它沒有數據)

UPDATE - download console app 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(); 
    } } 
} 

如果你能發現任何東西,我做錯了,可能導致這種情況發生,我會非常非常感謝:)

+0

也許它與那個'Tuple '有關? [http://stackoverflow.com/questions/13739348/why-i-could-not-serialize-a-tuple-in-c](http://stackoverflow.com/questions/13739348/why-i-could- not-serialize-a-tuple-in-c) – Rohrbs

+0

@Rohrbs - 感謝您的看法:)我確實在想 - 這就是爲什麼元組和字典都是以定製的,單獨的方式序列化的(請參閱名爲「tp1 「和」tp2「 - 」ipts「是字典的第三部分) – Nathan

+0

對不起,在仔細觀察後,沒有什麼會跳出來對我說。也許這裏演員'pp =>(int)pp.Key.Item1'?哪些值回到空值? tp1,tp2還是ipts?三個全部? – Rohrbs

回答

2

數組首先進行反序列化,然後再進行內部去極化。當循環瀏覽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<Tuple<int, int>, IPointTrainingSet>(); 

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

太棒了,謝謝 - 我會看看那個明天:) – Nathan

+0

那很有用 - 非常感謝! – Nathan

0

我能通過讓.NET處理List和Dictionary序列化來代替o來實現這個功能f試圖手動完成:

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,並有一些奇怪的結果,但這個簡單的版本似乎工作。

+0

非常感謝您的關注,但我已經擁有了這樣的工作原理 - 我自己也是這樣做的,因爲Mono在處理這些問題時處理得並不好(我將它在Microsoft環境中序列化並且在linux環境中對它進行反序列化)。 – Nathan

相關問題