Почему BinaryFormatter пытается привести объект типа, помеченного как [Serializable], к IConvertible? - PullRequest
6 голосов
/ 02 февраля 2012

Я понимаю, что в других местах хорошо известно, что сериализация ваших доменных объектов NHibernate, как правило, плохая идея.Мой вопрос здесь заключается в попытке понять, как работает BinaryFormatter, и почему приведенный ниже сценарий дает InvalidCastException.

Структура класса примерно выглядит следующим образом:

[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; }
}

СериализацияМетод выглядит следующим образом:

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

Иногда при вызове сериализации, например,

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

Я получу

Невозможно привести объект типа 'NHibernate.Collection..Generic.PersistentGenericBag`1 [Toy] 'для ввода' System.IConvertible '.

(все коллекции сопоставлены с семантикой мешка).

Даже NHibernate.Collection.Generic.PersistentGenericBag<T> помечено [Serializable]

Итак, учитывая, что все здесь помечено как [Serializable], почему бы BinaryFormatter пытаться вначале привести PersistentGenericBag к IConvertible?

Редактировать: Если это актуально, это под .NET 3.5 и NHibernate 3.1.0

1 Ответ

1 голос
/ 06 июля 2012

Имея класс Pet, унаследованный от System.Runtime.Serialization.ISerializable , теперь у нас есть полный контроль над тем, как класс Pet и его члены, в данном случае Toy, сериализуются и десериализуются. , Пожалуйста, смотрите System.Runtime.Serialization.ISerializable , для получения дополнительной информации о реализации System.Runtime.Serialization.ISerializable .

Пример ниже будет сериализовать, а затем десериализовать экземпляр класса Parent в байтовый массив и обратно.

Открытый метод, public GetObjectData (информация System.Runtime.Serialization.SerializationInfo, контекст System.Runtime.Serialization.StreamingContext) , вызывается при сериализации типа Pet; Сначала мы добавляем значение Int32, указывающее количество предметов в списке игрушек. Затем мы добавляем каждую игрушку из списка.

Защищенный конструктор, protected Pet (System.Runtime.Serialization.SerializationInfo info, контекст System.Runtime.Serialization.StreamingContext) , вызывается при десериализации этого типа. Сначала мы читаем количество предметов, которые были сохранены в списке игрушек, а затем используем его для чтения каждого экземпляра игрушки из сериализованного потока.

Обратите внимание, что для каждого экземпляра Toy, добавляемого в сериализованный поток, мы присваиваем ему другое имя; в этом случае мы просто добавили значение индекса к слову Toy; то есть "Toy1", "Toy2", ... Это потому, что каждому элементу в сериализованном потоке требуется уникальное имя. См .: System.Runtime.Serialization.ISerializable .

И, контролируя сериализацию / десериализацию списка Toys в Pet, мы можем устранить проблему невозможности сериализации / десериализации списка на основе типа: 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; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...