2010-02-01 22 views
5

Tôi đang làm một số tuần tự hóa các đối tượng db linq, chứa các lớp EntitySet và EntityRef..NET, C#: Cách thêm thuộc tính tuần tự hóa tùy chỉnh hoạt động như giao diện ISerializable

Tôi đã tìm thấy một cách khá dễ dàng để xử lý tuần tự hóa các lớp này, bằng cách sử dụng ISerializable để xử lý đúng các thành viên thuộc loại này (chuyển đổi chúng thành danh sách để tuần tự hóa và hoàn tác nó trên deserialization).

Tuy nhiên, nó sẽ thực sự tốt đẹp nếu tôi có thể làm:

[Serializable] 
[SerializeLinqEntities] 
partial class Person 
{ ... } 

Thay vì:

partial class Person : ISerializable 
{ 
    public virtual void GetObjectData(SerializationInfo si, StreamingContext ctxt) 
    { 
    EntitySerializer.Serialize(this, typeof(Person), si, ctxt); 
    } 

    protected Person(SerializationInfo si, StreamingContext ctxt) 
    { 
    EntitySerializer.Deerialize(this, typeof(Person), si, ctxt); 
    } 
} 

Có cách nào để làm điều này? Tôi nhìn qua các lớp serialization và dường như không thể tìm thấy bất kỳ cách nào để thiết lập thói quen lọc serialization tùy chỉnh (nơi tôi có thể tìm thuộc tính tùy chỉnh của tôi).

Cảm ơn!

+0

Hình như IClientFormatterSinkProvider và IServerFormatterSinkProvider sẽ cho phép tôi để cung cấp một BinaryFormatter với thiết lập tùy chỉnh SurrogateSelector tôi. Cảm ơn một lần nữa Sergey! – marq

+0

Hmm ... vì vậy, khi nó quay ra, Microsoft đã thực hiện điều này rất nhiều khó khăn hơn nó trông. Xem liên kết sau: http://www.123aspx.com/Rotor/RotorSrc.aspx?rot=40027 Các nhà cung cấp bồn rửa, vì nó quay ra, khá phức tạp và không đơn giản như việc triển khai. Tôi thực sự muốn họ cung cấp giao diện API tốt hơn để giao tiếp với serialization nhị phân ... – marq

Trả lời

7

Có, bạn có thể thực hiện việc này bằng cách triển khai các giao diện ISerializationSurrogateISurrogateSelector.

Something như thế này:

[AttributeUsage(AttributeTargets.Class)] 
public class SerializeLinqEntities : Attribute 
{ 
} 

public class LinqEntitiesSurrogate : ISerializationSurrogate 
{ 
    public void GetObjectData(
     object obj, SerializationInfo info, StreamingContext context) 
    { 
     EntitySerializer.Serialize(this, obj.GetType(), info, context); 
    } 

    public object SetObjectData(
     object obj, SerializationInfo info, 
     StreamingContext context, ISurrogateSelector selector) 
    { 
     EntitySerializer.Deerialize(obj, obj.GetType(), info, context); 
     return obj; 
    } 
} 


/// <summary> 
/// Returns LinqEntitySurrogate for all types marked SerializeLinqEntities 
/// </summary> 
public class NonSerializableSurrogateSelector : ISurrogateSelector 
{ 
    public void ChainSelector(ISurrogateSelector selector) 
    { 
     throw new NotImplementedException(); 
    } 

    public ISurrogateSelector GetNextSelector() 
    { 
     throw new NotImplementedException(); 
    } 

    public ISerializationSurrogate GetSurrogate(
     Type type, StreamingContext context, out ISurrogateSelector selector) 
    { 
     if (!type.IsDefined(typeof(SerializeLinqEntities), false)) 
     { 
      //type not marked SerializeLinqEntities 
      selector = null; 
      return null; 
     } 
     selector = this; 
     return new LinqEntitiesSurrogate(); 
    } 

} 

[SerializeLinqEntities] 
public class TestSurrogate 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

class Program 
{ 
    static void Main(string[] str) 
    { 

     var ns1 = new TestSurrogate {Id = 47, Name = "TestName"}; 
     var formatter = new BinaryFormatter(); 
     formatter.SurrogateSelector = new NonSerializableSurrogateSelector(); 

     using (var ms = new MemoryStream()) 
     { 
      formatter.Serialize(ms, ns1); 
      ms.Position = 0; 

      var ns2 = (TestSurrogate) formatter.Deserialize(ms); 
      // Check serialization 
      Debug.Assert(ns1.Id == ns2.Id); 
      Debug.Assert(ns1.Name == ns2.Name); 
     } 
    } 
} 
+0

Đó là chính xác những gì tôi muốn (ISurrogateSelector là chính xác những gì tôi đang tìm kiếm). Vì vậy, câu hỏi cuối cùng - có cách nào để sử dụng điều này với serialization tự động? Serializing của tôi đang xảy ra thông qua một cuộc gọi RPC (bằng cách sử dụng một MarshalByRefObject). – marq

+0

+1 Tôi thậm chí còn không nghĩ đến 'ISerializationSurrogate' bởi vì câu hỏi được nhắc đến một cách rõ ràng. Vấn đề duy nhất với giải pháp này là khi bạn không có quyền truy cập vào cá thể trình định dạng để thiết lập thuộc tính 'SurrogateSelector'. – Rory

+0

Trong WCF, bạn có thể dễ dàng sử dụng người thay thế (http://msdn.microsoft.com/en-us/library/ms733064.aspx). Tôi không sử dụng thay thế với .net remoting. Có thể Custom Sinks có thể giúp bạn (http://www.codeproject.com/KB/IP/customsinks.aspx). –

0

Thật không may, ISerializable là giao diện được thiết kế để cho phép bạn kiểm soát quá trình tuần tự hóa trong khi SerializableAttribute chỉ là một dấu hiệu cho biết "lớp này có thể được đăng theo thứ tự". Tuy nhiên, bạn có thể nhìn vào một cái gì đó như PostSharp để thêm chức năng này (hãy xem CompositionAspect).

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