我意识到在其他地方已经确定序列化您的 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();
我会得到
Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericBag`1[Toy]' to type 'System.IConvertible'.
(所有集合都使用包语义进行映射)。
甚至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 类的实例,然后将其反序列化为字节数组,然后再反序列化。
公共(public)方法 public GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 在 Pet 类型被序列化时被调用;首先,我们添加一个 Int32 值,指示 Toys 列表中的项目数。然后我们从列表中添加每个玩具。
protected 构造函数 protected Pet(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) 在反序列化此类型时调用。首先,我们读取存储在 Toys 列表中的项目数,然后使用它从序列化流中读取每个 Toy 实例。
请注意,对于添加到序列化流中的每个 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/