title: Serialized objects disappearing (BinaryFormatter)
body: <p><strong>Background</strong></p>
  
  <p>I have an object which I need to serialize in order to transfer to a high performance computing cluster for later use</p>
  
  <p>Previously, I've used the out-of-the-box binary formatter for my object which represents a statistical shape model and all worked happily</p>
  
  <p>My object became more complex and I decided to customize the serialization process by implementing ISerializable. I continue to support data stored in the previous format</p>
  
  <p><strong>The Problem</strong></p>
  
  <p>My problem is that one particular value appears to serialize successfully, but always has a value of null when I attempt deserialization.   (no error, just a very unpleasant, un-useful null)</p>
  
  <p>When I break at the point of serialization, I can see that the object is added to the SerializationInfo ok by inspecting the SerializationInfo and that it has values  (it's nothing fancy, but will post the code for it below)</p>
  
  <p>The serialization constructor is being called (I put a break-point there too), but when I inspect the SerializationInfo object of the constructor, it has no data  (it does have an entry, just no data)</p>
  
  <p><strong>UPDATE</strong> - download console app <a href="https://docs.google.com/file/d/0B_ITQGuqH0C4bDJoZXJGRzd0aUU/edit?usp=sharing" rel="nofollow">here</a>.  Thanks for looking</p>
  
  <p>or, look at code here:</p>
  
  <p><strong>The Code</strong></p>
  
  <p>Class causing problems:   (the PointProfiles property is the offending object)</p>
  
  <pre><code>   [Serializable]
      public class TrainingSet : ITrainingSet, ISerializable
      {
          public Dictionary&lt;Tuple&lt;int, int&gt;, IPointTrainingSet&gt; PointProfiles { get; set; }
  
          public PrincipalComponentAnalysis PointPCA { get; set; }
  
          public double[] AlignedMean { get; set; }
  
          public List&lt;Tuple&lt;string, ITransform&gt;&gt; Transforms { get; set; }
  
          public string[] FileNames { get; set; }
  
          private static Lazy&lt;BinaryFormatter&gt; formatter = new Lazy&lt;BinaryFormatter&gt;();
  
          public static ITrainingSet Load(Guid modelId)
          {
              ModelSample s = DataProxy&lt;ModelSample&gt;.AsQueryable().Where(m =&gt; 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 =&gt; pp.Key.Item1).ToArray());
              info.AddValue("tp2", PointProfiles.Select(pp =&gt; pp.Key.Item2).ToArray());
  
              var x = PointProfiles.Select(pp =&gt; (ProfileModel)pp.Value).ToArray();
              info.AddValue("ipts", x, typeof(ProfileModel[]));
  
              info.AddValue("am", AlignedMean);
  
              info.AddValue("tname", Transforms.Select(t =&gt; t.Item1).ToArray());
              info.AddValue("tval", Transforms.Select(t =&gt; 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("&lt;PointPCA&gt;k__BackingField", typeof(PrincipalComponentAnalysis)) as PrincipalComponentAnalysis;
                      PointProfiles = info.GetValue("&lt;PointProfiles&gt;k__BackingField", typeof(Dictionary&lt;Tuple&lt;int, int&gt;, IPointTrainingSet&gt;)) as Dictionary&lt;Tuple&lt;int, int&gt;, IPointTrainingSet&gt;;
                      AlignedMean = info.GetValue("&lt;AlignedMean&gt;k__BackingField", typeof(double[])) as double[];
                      Transforms = info.GetValue("&lt;Transforms&gt;k__BackingField", typeof(List&lt;Tuple&lt;string, ITransform&gt;&gt;)) as List&lt;Tuple&lt;string, ITransform&gt;&gt;;
                      FileNames = info.GetValue("&lt;FileNames&gt;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&lt;Tuple&lt;string, ITransform&gt;&gt;();
                      for(int i = 0;i &lt; tn.Length;i++)
                          Transforms.Add(new Tuple&lt;string,ITransform&gt;(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&lt;Tuple&lt;int, int&gt;, IPointTrainingSet&gt;();
                      for (int i = 0; i &lt; i1.Length; i++)
                          PointProfiles.Add(new Tuple&lt;int, int&gt;(i1[i], i2[i]), xxx[i]);
  
  
  
                      break;
  
                  default:
                      throw new NotImplementedException("TrainingSet version " + version + " is not supported");
              }
  
          }
  
          public TrainingSet()
          {
  
          }
      }
  </code></pre>
  
  <p>Profile class  (also serializable, this is the base class for ProfileModel which is listed next)</p>
  
  <pre><code>    [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&lt;PrincipalComponentAnalysis&gt;(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);
          }
  
      }
  </code></pre>
  
  <p>and (Finally) the ProfileModel class:</p>
  
  <pre><code>[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&lt;double&gt;(profiles.Length, profiles[0].G.Columns(), 0);
  
          int idx = 0;
          foreach (var pg in profiles.Select(p =&gt; 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();
      } }
  }
  </code></pre>
  
  <p>If you can spot anything I'm doing wrong that might cause this to happen, I'd be very very grateful :)</p>