0

I'm trying to serialize generic classes. My code is looking like following :

public class Entity<DescriptorType> {
   // some **data**

   protected void Desezialize(SerializationInfo info, StreamingContext context) {
      // read **data** from info
   }

   protected void GetData(SerializationInfo info, StreamingContext context) {
      // fill info with class instance **data**
   }
}

[Serializable]
public class StringEntity : Entity<string>, ISerializable {

   private StringEntity (SerializationInfo info, StreamingContext context) {
      Desezialize(info, context);
   }

   [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
   public void GetObjectData(SerializationInfo info, StreamingContext ctxt) {
      GetData(info, ctxt);
   }
}

Then I store my entities in a container that looks like this :

[Serializable]
public class EntityContainer: ISerializable {

   public List<StringEntity> StringEntities;

   private EntityContainer(SerializationInfo info, StreamingContext context) {
      StringEntities = (List<StringEntity>) (info.GetValue("StringEntities", typeof(List<StringEntity>));
   }

   public void GetObjectData(SerializationInfo info, StreamingContext context) {
      info.AddValue("StringEntities", StringEntities);
   }
}

And finally, I serialize and deserialize like this :

EntityContainer Load(string filename) {
   IFormatter formatter = new BinaryFormatter();
   Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
   return (EntityContainer) formatter.Deserialize(stream);
}

void Save(EntityContainer entities, string filename) {
   IFormatter formatter = new BinaryFormatter();
   Stream stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
   formatter.Serialize(stream, entities);
}

The serialization(save) is done fine. Well, I thing so. But for the deserialisation(load), the problem is that the contructor of StringEntity is never called.

I guess it's a problem with the generics ? (I'm from c++, I'm certainly misunderstanding something about c# generics).

Any idea ?

  • If the value is null why would the constructor be called? – jdweng Oct 12 '20 at 11:26
  • What do you mean ? Serialization step is going fine, and the list contains several objects of type StringEntity. The constructor should be called by the C# serializer (formatter.Deserialize()) isn't it ? – rod riggs Oct 12 '20 at 11:28

1 Answers1

0

BinaryFormatter more or less takes the memory representation of objects and just writes it down to a stream. This makes it rather fragile, changes in the internal representation of objects may make the data unrecoverable. Essentially BinaryFormatter just writes to the fields directly, bypassing any constructors, See how BinaryFormatter deserializes objects. I do not think this has anything to do with generics.

I would recommend using another serializer that gives you control of how objects are serialized. There are many alternatives that allows you to add or remove properties from objects while still maintaining backwards/forwards compatibility. I can recommend Protobuf.Net, Json.Net or the builtin xml serializer, but there are many other alternatives.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • the problem is that binary serializer fits perfectly my needs. Memory used (disk and RAM), non human readable files... – rod riggs Oct 12 '20 at 12:20
  • @rod riggs See [serialization format comparison](https://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text/). Protobuf.net is both much smaller and faster. If you want larger files you can always add some random data to the end. I have personally had problems where data saved with BinaryFormatter with one version of .Net was not readable after upgrading to a newer version. – JonasH Oct 12 '20 at 14:18