我意识到在其他地方已经建立了很好的基础,序列化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();

我会得到



(所有集合都使用bag语义映射)。

甚至NHibernate.Collection.Generic.PersistentGenericBag<T>也被标记为[Serializable]
因此,鉴于此处的所有内容都标记为[Serializable],为什么BinaryFormatter首先尝试将PersistentGenericBag转换为IConvertible?

编辑:如果相关,则在.NET 3.5和NHibernate 3.1.0下

最佳答案

通过让Pet类从System.Runtime.Serialization.ISerializable继承,我们现在可以完全控制Pet类及其成员(在本例中为Toy)如何序列化和反序列化。请参阅System.Runtime.Serialization.ISerializable,以获取有关实现System.Runtime.Serialization.ISerializable的更多信息。

下面的示例将序列化,然后将Parent类的实例反序列化为字节数组,然后再次返回。

在对Pet类型进行序列化时,将调用公用方法 public GetObjectData(System.Runtime.Serialization.SerializationInfo info,System.Runtime.Serialization.StreamingContext上下文);首先,我们添加一个Int32值,该值指示“玩具”列表中的项目数。然后,我们从列表中添加每个玩具。

当反序列化此类型时,将调用 protected 构造方法 protected Pet(System.Runtime.Serialization.SerializationInfo信息,System.Runtime.Serialization.StreamingContext上下文)。首先,我们读取存储在“玩具”列表中的项目数,然后使用该数量从序列化流中读取每个玩具实例。

请注意,对于添加到序列化流中的每个Toy实例,我们给它取一个不同的名称;在这种情况下,我们只需将索引的值附加到Toy单词上即可;即“Toy1”,“Toy2”,...这是因为序列化流中的每个项目都需要一个唯一的名称。请参阅:System.Runtime.Serialization.ISerializable

通过控制Pet中Toys列表的序列化/反序列化,我们可以消除无法基于以下类型对列表进行序列化/反序列化的问题: 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; }
}

关于c# - 为什么BinaryFormatter尝试将标记为[Serializable]的类型的对象强制转换为IConvertible?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9105487/

10-09 05:18