2012-02-02 28 views
6

Tôi nhận ra nó đã được thiết lập tốt ở nơi khác mà việc tuần tự hóa các đối tượng miền NHibernate của bạn thường là một ý tưởng tồi. Câu hỏi của tôi ở đây là cố gắng hiểu cách hoạt động của BinaryFormatter và tại sao kịch bản dưới đây mang lại hiệu suất InvalidCastException.Tại sao BinaryFormatter cố gắng truyền một đối tượng kiểu được đánh dấu [Serializable] thành IConvertible?

Cấu trúc lớp khoảng trông như thế này:

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

Phương pháp serialization trông như thế này:

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

Đôi khi gọi serialization ví dụ

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

tôi sẽ nhận được

Không thể cast đối tượng của loại 'NHibernate.Collection.Generic.PersistentGenericBag`1 [Toy]' gõ 'System.IConvertible'.

(tất cả các bộ sưu tập được ánh xạ với ngữ nghĩa của túi).

Thậm chí NHibernate.Collection.Generic.PersistentGenericBag<T> được đánh dấu [Serializable]

Vì vậy, cho rằng tất cả mọi thứ ở đây được đánh dấu là [Serializable] tại sao BinaryFormatter được cố gắng đúc PersistentGenericBag một IConvertible ở nơi đầu tiên?

Edit: Trong trường hợp nó có liên quan, đây là dưới .NET 3.5 và NHibernate 3.1.0

+0

Bạn nói điều này xảy ra "đôi khi" khi tuần tự hóa - mã này có được sử dụng trong ứng dụng đa luồng không? – LukeH

+0

Nó được sử dụng trong một ứng dụng web, nhưng theo kịch bản tôi thấy, tôi nghĩ rằng nó có lẽ không phải là một vấn đề đồng thời. Dường như nó có thể có nhiều khả năng liên quan đến việc tải chậm hơn. – Nathan

Trả lời

1

Bởi có những lớp kế thừa Pet từ System.Runtime.Serialization.ISerializable, bây giờ chúng tôi có quyền kiểm soát hoàn toàn cách thức lớp thú nuôi, và nó các thành viên, trong trường hợp này Toy, được sắp xếp theo thứ tự và không được sắp xếp theo thứ tự. Vui lòng xem System.Runtime.Serialization.ISerializable để biết thêm thông tin về cách triển khai System.Runtime.Serialization.ISerializable.

Mẫu dưới đây sẽ tuần tự hóa và sau đó hủy tuần tự hóa một cá thể của lớp cha thành một mảng byte và ngược lại.

Phương thức công khai, công khai GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context), được gọi khi loại Pet đang được đăng; đầu tiên chúng ta thêm một giá trị Int32 cho biết số lượng các mục trong danh sách Đồ chơi. Sau đó, chúng tôi thêm mỗi đồ chơi từ danh sách.

Nhà xây dựng được bảo vệ, Bảo vệ Thú cưng (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context), được gọi khi loại này bị loại bỏ. Đầu tiên chúng ta đọc số lượng các mục được lưu trữ trong danh sách Đồ chơi, sau đó sử dụng nó để đọc từng thể hiện Đồ chơi từ luồng được tuần tự hóa.

Hãy lưu ý rằng đối với mỗi trường hợp Đồ chơi được thêm vào luồng được tuần tự hóa, chúng tôi đặt cho nó một tên khác; trong trường hợp này, chúng ta chỉ cần thêm giá trị của chỉ mục vào từ Toy; tức là "Toy1", "Toy2", ... Điều này là do mỗi mục trong luồng được tuần tự hóa cần một tên duy nhất. Xem: System.Runtime.Serialization.ISerializable.

Và bằng cách kiểm soát tuần tự hóa/de-serialization danh sách Đồ chơi trong Pet, chúng tôi có thể loại bỏ sự cố không thể sắp xếp/hủy tuần tự danh sách dựa trên loại: 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

Điều này có thể có thể cung cấp một cơ chế để giải quyết vấn đề, nhưng không giải thích tại sao diễn viên lạ xảy ra ngay từ đầu, đó thực sự là điểm chính của câu hỏi. – Nathan

Các vấn đề liên quan