2010-03-10 26 views
6

Trong khi sử dụng mã này để serialize một đối tượng:Clone Tổng Object Graph

public object Clone() 
{ 
    var serializer = new DataContractSerializer(GetType()); 
    using (var ms = new System.IO.MemoryStream()) 
    { 
     serializer.WriteObject(ms, this); 
     ms.Position = 0; 
     return serializer.ReadObject(ms); 
    } 
} 

tôi đã nhận thấy rằng nó không sao chép các mối quan hệ. Có cách nào để thực hiện điều này không?

+0

tôi nhận thấy như nhau, nó có thể đi một vài cấp độ, nhưng chủ yếu là bạn kết thúc với một đồ thị một phần và vô dụng. – leppie

+0

@leppie - nó có thể được thực hiện, mặc dù ;-p –

Trả lời

16

Đơn giản chỉ cần sử dụng quá tải constructor chấp nhận preserveObjectReferences, và đặt nó vào đúng:

using System; 
using System.Runtime.Serialization; 

static class Program 
{ 
    public static T Clone<T>(T obj) where T : class 
    { 
     var serializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, true, null); 
     using (var ms = new System.IO.MemoryStream()) 
     { 
      serializer.WriteObject(ms, obj); 
      ms.Position = 0; 
      return (T)serializer.ReadObject(ms); 
     } 
    } 
    static void Main() 
    { 
     Foo foo = new Foo(); 
     Bar bar = new Bar(); 
     foo.Bar = bar; 
     bar.Foo = foo; // nice cyclic graph 

     Foo clone = Clone(foo); 
     Console.WriteLine(foo != clone); //true - new object 
     Console.WriteLine(clone.Bar.Foo == clone); // true; copied graph 

    } 
} 
[DataContract] 
class Foo 
{ 
    [DataMember] 
    public Bar Bar { get; set; } 
} 
[DataContract] 
class Bar 
{ 
    [DataMember] 
    public Foo Foo { get; set; } 
} 
+0

Duh! Tôi nên tìm kiếm nhiều gợi ý hơn! :) – leppie

+0

Điều này nên là cách tốt nhất như tôi có thể nhìn thấy ... thanx Marc, nhưng tôi có một vấn đề với Object.Object2.Object3, điều này có thể được vấn đề trên Serializer? –

1

Hoặc chú thích các lớp của bạn với [DataContract] hoặc thêm các loại con của bạn trong hàm tạo của DatacontractSerializer.

var knownTypes = new List<Type> {typeof(Class1), typeof(Class2), ..etc..}; 
var serializer = new DataContractSerializer(GetType(), knownTypes); 
+0

Thanx, điều này cũng làm việc quá;) –

0

Bạn cần trình nối tiếp nhị phân để duy trì nhận dạng đối tượng trong bước tuần tự hóa/deserialization.

+0

Có, nhưng tôi sử dụng SqlMetal để tạo ra các lớp học và kích hoạt/serialization: Unidirectional. Xin lỗi vì sự bất tiện này. –

+0

Tôi không thể hiểu cách bình luận của bạn liên quan đến câu trả lời của tôi ...? Nhìn vào mẫu mã do Darin Dimitrov cung cấp – Seb

+1

Xin lỗi @Seb, nhưng điều đó không đúng. DataContractSerializer * có thể * sao chép đồ thị thích hợp, và không phải là một serializer nhị phân. Ngược lại, không đúng là tất cả các trình tuần tự nhị phân * có thể * nhất thiết phải sao chép đồ thị. Hỗ trợ đồ thị và đầu ra nhị phân là các khái niệm trực giao. –

1

Để thực hiện một bản sao sâu bạn có thể xem xét sử dụng một serializer nhị phân:

public static object CloneObject(object obj) 
{ 
    using (var memStream = new MemoryStream()) 
    { 
     var binaryFormatter = new BinaryFormatter(
      null, 
      new StreamingContext(StreamingContextStates.Clone)); 
     binaryFormatter.Serialize(memStream, obj); 
     memStream.Seek(0, SeekOrigin.Begin); 
     return binaryFormatter.Deserialize(memStream); 
    } 
}