简体   繁体   English

为什么BinaryFormatter会尝试将标记为[Serializable]的类型的对象强制转换为IConvertible?

[英]Why would BinaryFormatter attempt to cast an object of type marked [Serializable] to IConvertible?

I realize it has been well-established elsewhere that serializing your NHibernate domain objects is generally a bad idea. 我意识到在其他地方已经很好地建立了序列化你的NHibernate域对象通常是一个坏主意。 My question here is in trying to understand how BinaryFormatter works, and why the scenario below yields the InvalidCastException . 我的问题是试图理解BinaryFormatter是如何工作的,以及为什么下面的场景会产生InvalidCastException

The class structure roughly looks 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 looks like this: 序列化方法如下所示:

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

Sometimes when calling Serialization eg 有时在调用序列化时例如

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

I will get 我会得到

Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericBag`1[Toy]' to type 'System.IConvertible'. 无法将'NHibernate.Collection.Generic.PersistentGenericBag`1 [Toy]'类型的对象强制转换为'System.IConvertible'。

(all collections are mapped with bag semantics). (所有集合都使用包语义进行映射)。

Even NHibernate.Collection.Generic.PersistentGenericBag<T> is marked [Serializable] 甚至NHibernate.Collection.Generic.PersistentGenericBag<T>标记为[Serializable]

So given that everything here is marked as [Serializable] why would BinaryFormatter be attempting to cast PersistentGenericBag to an IConvertible in the first place? 因此,鉴于此处的所有内容都标记为[Serializable]为什么BinaryFormatter会首先尝试将PersistentGenericBag强制转换为IConvertible?

Edit: In case it's relevant, this is under .NET 3.5 and NHibernate 3.1.0 编辑:如果它是相关的,这是在.NET 3.5和NHibernate 3.1.0下

By having the Pet class inherit from System.Runtime.Serialization.ISerializable , we now have complete control over how the Pet Class, and its members, in this case Toy, are serialized and de-serialized. 通过使Pet类继承自System.Runtime.Serialization.ISerializable ,我们现在可以完全控制Pet Class及其成员(在本例中为Toy)的序列化和反序列化。 Please see System.Runtime.Serialization.ISerializable , for more information about implementing System.Runtime.Serialization.ISerializable . 请参阅System.Runtime.Serialization.ISerializable ,有关实现的更多信息System.Runtime.Serialization.ISerializable

The sample below will serialize and then de-serialize an instance of the Parent class into a byte array and back again. 下面的示例将序列化,然后将Parent类的实例反序列化为字节数组,然后再返回。

The public method, public GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) , is called when the Pet type is being serialized; 在序列化Pet类型时,将调用公共方法public publicObject(System.Runtime.Serialization.SerializationInfo info,System.Runtime.Serialization.StreamingContext context) first we add an Int32 value indicating the number of items in the Toys list. 首先,我们添加一个Int32值,表示Toys列表中的项目数。 Then we add each Toy from the list. 然后我们从列表中添加每个玩具。

The protected constructor, protected Pet(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) , is called when this type is being de-serialized. 当反序列化此类型时,将调用受保护的构造函数, 受保护的Pet(System.Runtime.Serialization.SerializationInfo info,System.Runtime.Serialization.StreamingContext上下文) First we read the number of items that were stored in the Toys list, then use that to read each Toy instance from the serialized stream. 首先,我们读取存储在Toys列表中的项目数,然后使用它来从序列化流中读取每个Toy实例。

Please notice that for each Toy instance added to the serialized stream, we give it a different name; 请注意,对于添加到序列化流的每个Toy实例,我们给它一个不同的名称; in this case we simply appended the value of the index to the word Toy; 在这种情况下,我们只需将索引的值附加到单词Toy; ie "Toy1", "Toy2",... This is because each item in the serialized stream needs a unique name. 即“Toy1”,“Toy2”,......这是因为序列化流中的每个项都需要一个唯一的名称。 See: System.Runtime.Serialization.ISerializable . 请参阅: System.Runtime.Serialization.ISerializable

And by controlling the serialization/de-serialization of the Toys list in Pet, we can eliminate the problem of not being able to serialize/de-serialize the list based on the type: NHibernate.Collection.Generic.PersistentGenericBag . 通过控制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; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么不使用BinaryFormatter序列化未标记为Serializable的类? - Why classes not marked with Serializable cannot be serialized using BinaryFormatter? 无法将类型为“骰子”的对象转换为类型为“ System.IConvertible”的对象 - Unable to cast object of type 'Dice' to type 'System.IConvertible' 无法将类型为DataTable的对象转换为类型System.IConvertible - Unable to cast object of type DataTable to type System.IConvertible 无法将“MyType”类型的对象强制转换为“IMyInterface`1 [System.IConvertible]” - Unable to cast object of type 'MyType' to type 'IMyInterface`1[System.IConvertible]' 无法将类型为“数据”的对象转换为类型为“ System.IConvertible”的对象 - Unable to cast object of type 'Data' to type 'System.IConvertible' 如何确定是否可以在没有IConvertible的情况下将对象强制转换为其他类型 - How toDetermine if an object can be cast to a different type, without IConvertible '无法转换对象' System.String [] '键入' System.IConvertible '。 - 'Failed to cast object' System.String [] 'to type' System.IConvertible '.' 程序集中的类型未标记为可序列化 - Type in assembly is not marked as serializable SerializationException类型“未标记为可序列化” - 但它确实如此 - SerializationException Type “is not marked as serializable” - But it is 保留未标记为可序列化的对象 - Persist an object that is not marked as serializable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM