2012-02-02 7 views
6

私は、あなたのNHibernateドメインオブジェクトをシリアライズすることは、一般的には悪い考えであることが他のところでは確立されていることを認識しています。ここで私の質問は、BinaryFormatterの仕組みを理解しようとすることで、なぜ以下のシナリオでInvalidCastExceptionが得られるのかを理解しようとしています。なぜBinaryFormatterは[Serializable]とマークされた型のオブジェクトをIConvertibleにキャストしようとしますか?

クラス構造は、おおよそ次のようになります。シリアル化などを呼び出すときに時々

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

:シリアル化の方法は、次のようになります

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

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

私は 'System.IConvertible' を入力するタイプ 'NHibernate.Collection.Generic.PersistentGenericBag`1 [玩具]' のオブジェクトをキャストすること

ができないでしょう。

(すべてのコレクションはバッグセマンティクスでマップされています)。

はさえNHibernate.Collection.Generic.PersistentGenericBag<T>は、だからここにすべてがなぜBinaryFormatter最初の場所でIConvertibleにPersistentGenericBagをキャストしようとするだろう[Serializable]としてマークされていることを考えると[Serializable]

をマークされていますか?

編集:場合、それは、関連するだ、これはSystem.Runtime.Serialization.ISerializableからペットクラスの継承を有することにより、.NET 3.5とNHibernateは3.1.0

+0

これは、マルチスレッドアプリケーションで使用されているこのコードはシリアル化するときに「時には」発生すると言いますか? – LukeH

+0

これはWebアプリケーションで使用されていますが、私が見ているシナリオでは、おそらく並行性の問題ではないと思います。遅延読み込みに関連する可能性が高いようです。 – Nathan

答えて

1

の下で、我々は今、ペットクラス方法を完全に制御を持っており、そのこの場合、Toyのメンバーはシリアライズされ、デシリアライズされます。 System.Runtime.Serialization.ISerializableの実装の詳細については、System.Runtime.Serialization.ISerializableを参照してください。

以下のサンプルは、Parentクラスのインスタンスをシリアル化してから、逆シリアル化してバイト配列にして、再び元に戻します。

パブリックメソッド、公共GetObjectData(System.Runtime.Serialization.SerializationInfo情報、System.Runtime.Serialization.StreamingContextコンテキスト)は、ペットの種類がシリアライズされるときに呼び出されます。最初に、Toysリストの項目数を示すInt32値を追加します。次に、各Toyをリストから追加します。このタイプは、デシリアライズされているときに

protectedコンストラクタ

保護されたペット(System.Runtime.Serialization.SerializationInfo情報、System.Runtime.Serialization.StreamingContextコンテキスト)は、と呼ばれています。最初に、Toysリストに格納されている項目の数を読み取り、それを使用して、一連のストリームから各Toyインスタンスを読み取ります。

シリアル化されたストリームに追加された各Toyインスタンスに対して、別の名前を付けることに注意してください。この場合、単にインデックスの値をToyという単語に追加しました。つまり、 "Toy1"、 "Toy2"、...これは、シリアライズされたストリームの各項目に固有の名前が必要なためです。参照:System.Runtime.Serialization.ISerializable

ペットのトイリストのシリアル化/逆シリアル化を制御することで、タイプに基づいてリストをシリアライズ/デシリアライズできないという問題を排除できます。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; } 
} 
+0

これは、問題を回避するためのメカニズムを提供する可能性がありますが、最初は奇妙なキャストが発生した理由を説明していませんが、これは本当に問題の要点です。 – Nathan

関連する問題