2010-03-04 22 views
27

chúng tôi có một số vấn đề với việc sắp xếp một danh sách trống. đây một số mã trong .NET sử dụng CF 2,0protobuf-net: Nối tiếp một danh sách trống

//Generating the protobuf-msg 
ProtoBufMessage msg = new ProtoBufMessage(); 
msg.list = new List<AnotherProtobufMessage>(); 
// Serializing and sending throw HTTP-POST 
MemoryStream stream = new MemoryStream(); 
Serializer.Serialize(stream, msg); 
byte[] bytes = stream.ToArray(); 
HttpWebRequest request = createRequest(); 
request.ContentLength = bytes.Length ; 

using (Stream httpStream = request.GetRequestStream()) 
{    
     httpStream.Write(bytes, 0, bytes.Length); 
} 

chúng tôi đã nhận một ngoại lệ, khi chúng tôi cố gắng viết trên luồng (bytes.length ra khỏi phạm vi). Nhưng một loại có Danh sách trống không được là 0 byte, phải (loại thông tin?)?

Chúng tôi cần loại gửi này, bởi vì trong Phản hồi là các thư từ Máy chủ cho khách hàng của chúng tôi.

Trả lời

31

Định dạng dây (được xác định bởi google - không nằm trong kiểm soát của tôi!) Chỉ gửi dữ liệu cho các mục. Không có sự phân biệt giữa danh sách trống và danh sách rỗng. Vì vậy, nếu không có dữ liệu để gửi - có, độ dài là 0 (nó là một định dạng rất tiết kiệm ;-p).

Bộ đệm giao thức không bao gồm bất kỳ siêu dữ liệu loại nào trên dây. Một dấu hiệu phổ biến khác ở đây là bạn có thể giả định thuộc tính danh sách của bạn được tự động khởi tạo là rỗng, nhưng nó sẽ không được (trừ khi mã của bạn làm điều đó, có lẽ trong trình khởi tạo trường hoặc hàm tạo).

Dưới đây là một hack hoàn toàn khả thi:

[ProtoContract] 
class SomeType { 

    [ProtoMember(1)] 
    public List<SomeOtherType> Items {get;set;} 

    [DefaultValue(false), ProtoMember(2)] 
    private bool IsEmptyList { 
     get { return Items != null && Items.Count == 0; } 
     set { if(value) {Items = new List<SomeOtherType>();}} 
    } 
} 

Hacky có thể, nhưng nó phải làm việc. Bạn cũng có thể mất Items "thiết lập" nếu bạn muốn và chỉ việc kéo thả bool:

[ProtoMember(1)] 
    public List<SomeOtherType> Items {get {return items;}} 
    private readonly List<SomeOtherType> items = new List<SomeOtherType>(); 

    [DefaultValue(false), ProtoMember(2)] 
    private bool IsEmptyList { 
     get { return items.Count == 0; } 
     set { } 
    } 
0
public List<NotificationAddress> BccAddresses { get; set; } 

bạn có thể thay bằng:

private List<NotificationAddress> _BccAddresses; 
public List<NotificationAddress> BccAddresses { 
    get { return _BccAddresses; } 
    set { _BccAddresses = (value != null && value.length) ? value : null; } 
} 
1

Như @Marc nói, định dạng dây chỉ gửi dữ liệu cho các mục, do đó, để biết danh sách có trống hay không, bạn phải thêm thông tin đó vào luồng.
Thêm bất động sản thêm để cho biết bộ sưu tập ban đầu là rỗng hoặc không phải là dễ dàng, nhưng nếu bạn không muốn thay đổi định nghĩa kiểu ban đầu bạn có thêm hai lựa chọn:

Serialize Sử dụng Surrogate

Các loại thay thế sẽ có thuộc tính bổ sung (giữ nguyên kiểu gốc của bạn) và sẽ khôi phục trạng thái ban đầu của danh sách: null, với các mục hoặc rỗng.

[TestMethod] 
    public void SerializeEmptyCollectionUsingSurrogate_RemainEmpty() 
    { 
     var instance = new SomeType { Items = new List<int>() }; 

     // set the surrogate 
     RuntimeTypeModel.Default.Add(typeof(SomeType), true).SetSurrogate(typeof(SomeTypeSurrogate)); 

     // serialize-deserialize using cloning 
     var clone = Serializer.DeepClone(instance); 

     // clone is not null and empty 
     Assert.IsNotNull(clone.Items); 
     Assert.AreEqual(0, clone.Items.Count); 
    } 

    [ProtoContract] 
    public class SomeType 
    { 
     [ProtoMember(1)] 
     public List<int> Items { get; set; } 
    } 

    [ProtoContract] 
    public class SomeTypeSurrogate 
    { 
     [ProtoMember(1)] 
     public List<int> Items { get; set; } 

     [ProtoMember(2)] 
     public bool ItemsIsEmpty { get; set; } 

     public static implicit operator SomeTypeSurrogate(SomeType value) 
     { 
      return value != null 
       ? new SomeTypeSurrogate { Items = value.Items, ItemsIsEmpty = value.Items != null && value.Items.Count == 0 } 
       : null; 
     } 

     public static implicit operator SomeType(SomeTypeSurrogate value) 
     { 
      return value != null 
       ? new SomeType { Items = value.ItemsIsEmpty ? new List<int>() : value.Items } 
       : null; 
     } 
    } 


Hãy loại của bạn Extensible

protobuf-net cho thấy giao diện IExtensible cho phép bạn mở rộng các loại để các lĩnh vực có thể được thêm vào một thông điệp mà không cần bất cứ điều gì phá vỡ (đọc thêm here) . Để sử dụng phần mở rộng protobuf-net, bạn có thể kế thừa lớp Extensible hoặc triển khai giao diện IExtensible để tránh ràng buộc thừa kế.
Bây giờ loại của bạn là "có thể mở rộng", bạn xác định các phương pháp [OnSerializing][OnDeserialized] để thêm các chỉ số mới sẽ được tuần tự hóa vào luồng và được khử tuần tự từ khi tạo lại đối tượng với trạng thái ban đầu.
Ưu điểm là bạn không cần phải xác định thuộc tính mới cũng như loại mới là người thay thế, khuyết điểm là IExtensible không được hỗ trợ nếu loại của bạn có loại phụ được xác định trong kiểu mô hình của bạn.

[TestMethod] 
    public void SerializeEmptyCollectionInExtensibleType_RemainEmpty() 
    { 
     var instance = new Store { Products = new List<string>() }; 

     // serialize-deserialize using cloning 
     var clone = Serializer.DeepClone(instance); 

     // clone is not null and empty 
     Assert.IsNotNull(clone.Products); 
     Assert.AreEqual(0, clone.Products.Count); 
    } 

    [ProtoContract] 
    public class Store : Extensible 
    { 
     [ProtoMember(1)] 
     public List<string> Products { get; set; } 

     [OnSerializing] 
     public void OnDeserializing() 
     { 
      var productsListIsEmpty = this.Products != null && this.Products.Count == 0; 
      Extensible.AppendValue(this, 101, productsListIsEmpty); 
     } 

     [OnDeserialized] 
     public void OnDeserialized() 
     { 
      var productsListIsEmpty = Extensible.GetValue<bool>(this, 101); 
      if (productsListIsEmpty) 
       this.Products = new List<string>(); 
     } 
    } 
Các vấn đề liên quan