Why would BinaryFormatter try to apply an object of the type indicated by [Serializable] to IConvertible?

I understand that it has worked well in other places, that serializing NHibernate domain objects is usually a bad idea. My question here is trying to understand how BinaryFormatter works, and why the script below gives an InvalidCastException .

The class structure looks something like this:

 [Serializable] public class Parent { public virtual Child child{get; set;} } [Serializable] public class Child { public virtual ICollection<GrandChild> GrandChildren { get; set; } } [Serializable] public class GrandChild { public virtual Pet pet{get; set;} } [Serializable] public class Pet { public virtual IList<Toy> Toys { get; set; } } [Serializable] public class Toy { public string ToyName { get; set; } } 

The serialization method is as follows:

 public static byte[] Serialize(this object t) { using (var ms = new MemoryStream()) { BinarySerializer.Serialize(ms, t); return ms.ToArray(); } } 

Sometimes when calling Serialization, for example

  Parent p = new Parent() ....; p.Serialize(); 

I will get

Cannot pass an object of type "NHibernate.Collection.Generic.PersistentGenericBag`1 [Toy]" to enter "System.IConvertible".

(all collections are displayed with the semantics of the package).

Even NHibernate.Collection.Generic.PersistentGenericBag<T> marked [Serializable]

So, given that everything here is designated as [Serializable] , why does the BinaryFormatter try to use the PersistentGenericBag for IConvertible in the first place?

Edit: In case it matters, it is under .NET 3.5 and NHibernate 3.1.0

+6
source share
1 answer

Having inherited the Pet class from System.Runtime.Serialization.ISerializable , we now have full control over how the Pet class and its members in this Case Toy are serialized and de-serialized. See System.Runtime.Serialization.ISerializable , for more information on implementing System.Runtime.Serialization.ISerializable .

The example below will serialize and then de-serialize an instance of the Parent class into an array of bytes and vice versa.

The public method, public GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) , is called upon serialization of type Pet; first add an Int32 value indicating the number of items in the Toys list. Then add each Toy from the list.

The protected constructor Pet (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) is called when this type is de-serialized. First we read the number of items that have been saved in the Toys list, then use this to read each instance of Toy from a serialized stream.

Note that for each instance of Toy added to the serialized stream, we give it a different name; in this case, we simply added the index value to the word "Toy"; that is, "Toy1", "Toy2", ... This is because each element in the serialized stream needs a unique name. See: System.Runtime.Serialization.ISerializable .

And by controlling the serialization / de-serialization of the Toys list in Pet, we can fix the problem of the inability to serialize / de-serialize the list based on: NHibernate.Collection.Generic. PersistentGenericBag .

 using System; using System.Collections.Generic; using System.Linq; using System.Text; static class Program { static void Main(string[] args) { Parent p = new Parent(); p.child = new Child(); p.child.GrandChildren = new List<GrandChild>(); p.child.GrandChildren.Add(new GrandChild { pet = new Pet() }); p.child.GrandChildren.First().pet.Toys = new List<Toy>(); p.child.GrandChildren.First().pet.Toys.Add(new Toy { ToyName = "Test" }); byte[] result = Serialize(p); Parent backAgain = Deserialize(result); } public static System.Runtime.Serialization.Formatters.Binary.BinaryFormatter BinarySerializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); public static byte[] Serialize(Parent p) { using (var ms = new System.IO.MemoryStream()) { BinarySerializer.Serialize(ms, p); return ms.ToArray(); } } public static Parent Deserialize( byte[] data) { using (var ms = new System.IO.MemoryStream(data)) { return (Parent)BinarySerializer.Deserialize(ms); } } } [Serializable] public class Parent { public virtual Child child { get; set; } } [Serializable] public class Child { public virtual ICollection<GrandChild> GrandChildren { get; set; } } [Serializable] public class GrandChild { public virtual Pet pet { get; set; } } [Serializable] public class Pet : System.Runtime.Serialization.ISerializable { public Pet() { } // called when de-serializing (binary) protected Pet(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { Toys = new List<Toy>(); int counter = info.GetInt32("ListCount"); for (int index = 0; index < counter; index++) { Toys.Add((Toy)info.GetValue(string.Format("Toy{0}",index.ToString()),typeof(Toy))); } } // called when serializing (binary) public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { info.AddValue("ListCount", Toys.Count); for (int index = 0; index < Toys.Count; index++) { info.AddValue(string.Format("Toy{0}", index.ToString()), Toys[index], typeof(Toy)); } } public virtual IList<Toy> Toys { get; set; } } [Serializable] public class Toy { public string ToyName { get; set; } } 
+1
source

Source: https://habr.com/ru/post/907445/


All Articles