2010-03-04 23 views
27

हमें खाली सूची को क्रमबद्ध करने में कुछ समस्याएं हैं। यहाँ .NET में कुछ कोड सीएफ 2,0प्रोटोबफ-नेट: खाली सूची को क्रमबद्ध करना

//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); 
} 

हम एक अपवाद है, का उपयोग करते हुए जब हम धारा (bytes.length सीमा से बाहर) पर लिखने के लिए प्रयास करें। लेकिन एक खाली सूची वाला एक प्रकार 0 बाइट्स नहीं होना चाहिए, दाएं (प्रकार-सूचना?)?

हमें इस प्रकार की भेजने की आवश्यकता है, क्योंकि प्रतिक्रिया में हमारे ग्राहक के लिए सर्वर से संदेश हैं।

उत्तर

31

तार प्रारूप (Google द्वारा परिभाषित - मेरे नियंत्रण में नहीं!) केवल आइटम के लिए डेटा भेजता है। यह खाली सूची और शून्य सूची के बीच कोई भेद नहीं करता है। तो यदि भेजने के लिए कोई डेटा नहीं है - हाँ, लंबाई 0 है (यह एक बहुत ही मितव्ययी प्रारूप है; -पी)।

प्रोटोकॉल बफर में तार पर किसी भी प्रकार का मेटाडेटा शामिल नहीं है।

यहां एक और आम गॉचा यह है कि आप मान सकते हैं कि आपकी सूची संपत्ति स्वचालित रूप से खाली के रूप में तुरंत चालू हो जाती है, लेकिन यह तब तक नहीं होगा (जब तक आपका कोड ऐसा नहीं करता है, शायद फ़ील्ड प्रारंभकर्ता या कन्स्ट्रक्टर में)।

यहाँ एक व्यावहारिक हैक है:

[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 शायद, लेकिन यह काम करना चाहिए। तुम भी और Items "सेट" अगर आप चाहते हैं खोना बस छोड़ 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; } 

आप के साथ की जगह ले सकता:

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

रूप @Marc कहा, तार प्रारूप केवल भेजता है वस्तुओं के लिए डेटा, ताकि यह पता चल सके कि सूची खाली या शून्य थी, तो आपको उस जानकारी को स्ट्रीम में जोड़ना होगा।
इंगित करते हैं कि मूल संग्रह या खाली था नहीं अतिरिक्त संपत्ति जोड़ना आसान है, लेकिन आप एक और दो विकल्प हैं यदि आप मूल प्रकार परिभाषा को संशोधित नहीं करना चाहती:

को क्रमानुसार सरोगेट

सरोगेट प्रकार का उपयोग करना अतिरिक्त संपत्ति होगी (आपके मूल प्रकार को छूटे रहेंगे) और सूची की मूल स्थिति को पुनर्स्थापित कर देगा: शून्य, वस्तुओं या खाली के साथ।

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


आपका प्रकार एक्सटेंसिबल बनाओ

Protobuf शुद्ध IExtensible इंटरफ़ेस जो आप प्रकार का विस्तार करने के लिए इतना है कि खेतों में कुछ भी तोड़ने के बिना संदेश में जोड़ा जा सकता अनुमति देते हैं सुझाव है (अधिक here पढ़ें) । प्रोटोबफ-नेट एक्सटेंशन का उपयोग करने के लिए आप Extensible कक्षा का उत्तराधिकारी प्राप्त कर सकते हैं या विरासत बाधा से बचने के लिए IExtensible इंटरफ़ेस को कार्यान्वित कर सकते हैं।
अब आपका प्रकार "एक्स्टेंसिबल" है जिसे आप [OnSerializing] और [OnDeserialized] विधियों को परिभाषित करने के लिए नए संकेतक जोड़ने के लिए परिभाषित करते हैं, जो ऑब्जेक्ट को अपने मूल स्थिति के साथ पुनर्निर्माण करते समय धारा से क्रमबद्ध किया जाता है और इससे deserialized किया जाता है।
पेशेवर यह है कि आपको नए गुणों को परिभाषित करने की आवश्यकता नहीं है और न ही नए प्रकार सरोगेट्स के रूप में परिभाषित करने की आवश्यकता है, विपक्ष यह है कि IExtensible समर्थित नहीं है यदि आपके प्रकार के प्रकार आपके प्रकार के मॉडल में परिभाषित हैं।

[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>(); 
     } 
    } 
संबंधित मुद्दे