2010-06-16 18 views
21

मैं BinaryFormatter के साथ एक DynamicObject वर्ग क्रमानुसार करने की कोशिश की है, लेकिन:गतिशील वस्तु क्रमबद्धता

  • आउटपुट फ़ाइल बहुत बड़ी है, बिल्कुल नहीं तार के अनुकूल है
  • परिपत्र संदर्भ नहीं संभाला (जबकि serializing अटक)

के बाद से serializing एक DynamicObject अपने आप में बहुत कम मतलब है, यहाँ वर्ग मैं क्रमानुसार करने की कोशिश की है:

[Serializable()] 
class Entity 
    : DynamicObject, ISerializable 
{ 

    IDictionary<string, object> values = new Dictionary<string, object>(); 

    public Entity() 
    { 

    } 

    protected Entity(SerializationInfo info, StreamingContext ctx) 
    { 
     string fieldName = string.Empty; 
     object fieldValue = null; 

     foreach (var field in info) 
     { 
      fieldName = field.Name; 
      fieldValue = field.Value; 

      if (string.IsNullOrWhiteSpace(fieldName)) 
       continue; 

      if (fieldValue == null) 
       continue; 

      this.values.Add(fieldName, fieldValue); 
     } 

    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     this.values.TryGetValue(binder.Name, out result); 

     return true; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     this.values[binder.Name] = value; 

     return true; 
    }   

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) 
    {    
     foreach (var kvp in this.values) 
     { 
      info.AddValue(kvp.Key, kvp.Value);     
     } 
    } 

} 

(मुझे लगता है मैं एक ExpandoObject का इस्तेमाल किया है सकते हैं, लेकिन है कि एक और कहानी है लगता है।)

यहाँ एक सरल परीक्षण कार्यक्रम है: मदद मुझे एक नजर है

static void Main(string[] args) 
    { 
     BinaryFormatter binFmt = new BinaryFormatter(); 

     dynamic obj = new Entity(); 
     dynamic subObj = new Entity(); 
     dynamic obj2 = null; 

     obj.Value = 100; 
     obj.Dictionary = new Dictionary<string, int>() { { "la la la", 1000 } }; 

     subObj.Value = 200; 
     subObj.Name = "SubObject"; 

     obj.Child = subObj; 

     using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate)) 
     { 
      binFmt.Serialize(stream, obj);     
     } 

     using (var stream = new FileStream("test.txt", FileMode.Open)) 
     { 
      try 
      { 
       obj2 = binFmt.Deserialize(stream);      
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
      }     
     } 

     Console.ReadLine(); 

    } 

कुछ breakpoints यहाँ लाना और वहाँ obj2 सामग्री पर और ऐसा लगता है कि मूल डेटा सही ढंग से deserialized है, हालांकि उपरोक्त कमियों के साथ अगर आप कल्पनाशील हो और डेटा चारों ओर ले जाएँ।

मैंने मार्क ग्रेवेल के प्रोटोबफ-नेट पर एक नज़र डाली थी, लेकिन मुझे वास्तव में इस तरह के संदर्भ में इसका उपयोग करने का यकीन नहीं है (मुझे यह भी यकीन नहीं है कि मैंने रिपोजिटरी से सही संस्करण उठाया है, लेकिन हे) ।

मुझे पता है कि यह शब्दों की तुलना में अधिक कोड है, लेकिन मुझे नहीं लगता कि मैं परिदृश्य को किसी भी बेहतर तरीके से समझा सकता हूं। कृपया यह बताएं कि क्या इस प्रश्न को स्पष्ट करने के लिए मैं कुछ जोड़ सकता हूं।

किसी भी मदद की बहुत सराहना की जाती है।

+0

संदर्भ के लिए, * Protobuf शुद्ध * वर्तमान के लिए कोई समर्थन नहीं है 'dynamic'। मैं serialization के लिए एक डीटीओ परत में जाने का सुझाव देना होगा। –

+0

@Marc - धन्यवाद, मैं उसमें देख लूंगा। अभी भी अन्य सुझावों के लिए भी खुला है। – Raine

+0

अच्छी तरह से, दीर्घकालिक यह कुछ है जो मैं प्रोटोबफ-नेट में समर्थन करने की योजना बना रहा हूं। लेकिन मैं इस समय कुछ भी वादा नहीं कर सकता। –

उत्तर

12

मैं 98% निश्चित हूं कि यह अनुक्रम एक गतिशील वस्तु के लिए काम करेगा। एक expando वस्तु को

  1. परिवर्तित वस्तु
  2. डाली expando वस्तु
  3. उपयोग Protobuf शुद्ध Serializer.Serialize/.Deserialize सामान्य
  4. परिवर्तित शब्दकोश के अनुसार वस्तु expando को
प्रकार शब्दकोश का होना

आप वस्तुओं को ट्रांसफर करने के लिए नाम/मूल्य जोड़े के संग्रह में परिवर्तित कर सकते हैं।

यह गतिशील क्या कर सकता है इसका एक छोटा सबसेट है, लेकिन शायद यह आपके लिए पर्याप्त है।

ऊपर कुछ रूपांतरणों को संभालने के लिए कुछ कस्टम कोड है जो मुझे रुचि दिखाते हैं तो मैं आपको दिखा सकता हूं।

मेरे पास कोई समाधान नहीं है जब गतिशील कक्षा में प्लेसहोल्डर हो। इस मामले के लिए मैं आपको टाइप प्राप्त करने और धारावाहिक/deserialize करने के लिए एक स्विच स्टेटमेंट का उपयोग करने की सलाह देता हूं जैसा कि आपको चाहिए। इस आखिरी मामले के लिए, आपको यह इंगित करने के लिए कुछ देना होगा कि आपको किस प्रकार की जेनेरिक deserialization की आवश्यकता है (स्ट्रिंग/आईडी/पूरी तरह से योग्य प्रकार का नाम/आदि)। धारणा यह है कि आप अपेक्षित प्रकार की सूची से निपट रहे हैं।

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

refs:

+0

हाँ, कुछ कोड वास्तव में अच्छा होगा! – ErikE

+0

@ErikE: मुझे उस समय एक उदाहरण करना चाहिए था। मैंने आपके लिए उत्तर में कुछ संदर्भ लिंक डाले हैं। उम्मीद है कि उन मदद करते हैं। – sgtz

+0

यह काम नहीं करता है क्योंकि ProtoBuf-net प्रकार ऑब्जेक्ट के मानों को क्रमबद्ध नहीं करेगा। अंतर्निहित शब्दकोश प्रकार 'IDictionary 'प्रकार का है। – ChrisW

9

मुझे यकीन नहीं है कि JSON आपके सेनेरियो में स्वीकार्य होगा, लेकिन यदि मैंने गतिशील प्रकारों को क्रमबद्ध करने के लिए Json.net (http://json.codeplex.com) का उपयोग किया है। यह काफी अच्छी तरह से काम करता है, यह तेज़ है, और आउटपुट आकार में छोटा है। जबकि Json.net सीधे गतिशील वस्तुओं को वापस नहीं करता है, Json.Net के deserialized आउटपुट को किसी भी गतिशील प्रकार में परिवर्तित करना बहुत आसान है। नीचे दिए गए उदाहरण में मैं अपने डायनामिक प्रकार के रूप में ExpandoObject का उपयोग कर रहा हूं। नीचे दिया गया कोड वह है जो मैंने फेसबुक ग्राफ टूलकिट में उपयोग किया है। मूल स्रोत के लिए इस लिंक देखें: http://facebookgraphtoolkit.codeplex.com/SourceControl/changeset/view/48442#904504

public static dynamic Convert(string s) { 
      object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(s); 
      if (obj is string) { 
       return obj as string; 
      } else { 
       return ConvertJson((JToken)obj); 
      } 
    } 

    private static dynamic ConvertJson(JToken token) { 
     // FROM : http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx 
     // Ideally in the future Json.Net will support dynamic and this can be eliminated. 
     if (token is JValue) { 
      return ((JValue)token).Value; 
     } else if (token is JObject) { 
      ExpandoObject expando = new ExpandoObject(); 
      (from childToken in ((JToken)token) where childToken is JProperty select childToken as JProperty).ToList().ForEach(property => { 
       ((IDictionary<string, object>)expando).Add(property.Name, ConvertJson(property.Value)); 
      }); 
      return expando; 
     } else if (token is JArray) { 
      List<ExpandoObject> items = new List<ExpandoObject>(); 
      foreach (JToken arrayItem in ((JArray)token)) { 
       items.Add(ConvertJson(arrayItem)); 
      } 
      return items; 
     } 
     throw new ArgumentException(string.Format("Unknown token type '{0}'", token.GetType()), "token"); 
    } 
+0

धन्यवाद, दिलचस्प। मैं एक आशंका देखेंगे। मेरी एकमात्र चिंता यह है कि यह (कथित तौर पर) बाइनरी क्रमिकरण के रूप में कुशल नहीं होगा। – Raine

+2

मेरी समस्याओं के कुछ अलग समाधानों को आजमाने के बाद, आपका कोड वह कोड था जिसने मुझे इसकी आवश्यकता थी। इसलिए, हालांकि आपके उत्तर ने ओपी को जितना भी किया उतना मदद नहीं की है, फिर भी मैं इसे खोजने की सराहना करता हूं! :) –

0

अगर SharpSerializer गतिशील वस्तुओं का समर्थन करता है मैं नहीं जानता, लेकिन इसके लायक एक कोशिश हो सकती है:

http://www.sharpserializer.com/en/index.html

1

सबसे पहले, के आकार अपने फ़ाइल 2 चीजों पर निर्भर करती है (यदि मैं समझता हूं कि बाइनरीफॉर्मेटर कैसे काम करता है, तो कृपया मुझे सही करें यदि मैं गलत हूं):

  1. वास्तविक मानों का आकार धारावाहिक ized, और
  2. नाम SerializationInfo.AddValue विधि के साथ ऑब्जेक्ट के मानों को क्रमबद्ध करने के लिए उपयोग किए जाने वाले नाम, जो आउटपुट फ़ाइल में संग्रहीत हैं, इसलिए मान उसी नाम के साथ deserialization के दौरान उपयोग किया जा सकता है।

जाहिर है, # 1 आपकी सबसे बड़ी मंदी का कारण बनने जा रहा है, जिसे केवल उन वस्तुओं को अनुकूलित करके कम किया जा सकता है जिन्हें आप क्रमबद्ध करने की कोशिश कर रहे हैं।

क्योंकि आप गतिशील वस्तुओं का उपयोग कर रहे हैं, लगभग # 2 के कारण लगभग अनजाने में छोटे आकार की वृद्धि अपरिहार्य है। यदि आप ऑब्जेक्ट के सदस्यों के समय और नामों को समय से पहले जानते थे, तो आप ऑब्जेक्ट के प्रत्येक सदस्य को बहुत ही कम, अनुक्रमिक रूप से निर्धारित नाम ("1", "2", "3" इत्यादि) दे सकते हैं जैसा कि आपने पुनरावृत्त किया था ऑब्जेक्ट के सदस्यों पर, उन्हें SerializationInfo.AddValue के माध्यम से जोड़ना। फिर, deserialization के दौरान, आप SerializationInfo.GetValue का उपयोग उसी अनुक्रमिक रूप से निर्धारित नाम के साथ कर सकते हैं, और deserialization deserialized होने के वास्तविक नामों के बावजूद, ठीक उसी तरह काम करेगा, जब तक आप ऑब्जेक्ट के सदस्यों के माध्यम से उसी क्रम में पुन: इसमें जोड़ा गया है, यह केवल आपको प्रति सदस्य औसतन 4 या 5 बाइट बचा सकता है, लेकिन उन छोटी मात्रा में बड़ी वस्तुओं में वृद्धि हो सकती है।

@Raine: (। मुझे लगता है मैं एक ExpandoObject इस्तेमाल किया जा सकता था लगता है, लेकिन यह एक और कहानी है)

नहीं

तो; मैंने आपके Entity कक्षा के बजाय ExpandoObject का उपयोग करने के लिए अपना कोड नमूना बदल दिया, और मुझे SerializationException पर फेंक दिया। ExpandoObject को SerializableAttribute के साथ चिह्नित नहीं किया गया है, और इसमें उपयुक्त कन्स्ट्रक्टरों को deserialized या serialized होने के लिए नहीं है। हालांकि, इसका मतलब यह नहीं है कि यदि आप वास्तव में करना चाहते हैं तो ExpandoObject का उपयोग नहीं कर सकते: यह IDictionary<string, object> लागू करता है, जो बदले में ICollection<KeyValuePair<string, object>> लागू करता है। इस प्रकार, ExpandoObject उदाहरण KeyValuePair<string, object> उदाहरणों का संग्रह है, जो क्रमबद्ध के रूप में चिह्नित हैं। तो, आप एक ExpandoObject serialize कर सकते हैं, लेकिन आप इसे ICollection<KeyValuePair<string, object>> के रूप में डालना होगा और प्रत्येक KeyValuePair<string, object> को व्यक्तिगत रूप से क्रमबद्ध करना होगा। हालांकि, यह आपके मूल कोड नमूना को अनुकूलित करने के मामले में व्यर्थ होगा, क्योंकि यह उतना ही अधिक फ़ाइल स्थान लेता है।

संक्षेप में, मुझे नहीं लगता कि आप किसी भी तरह से गतिशील वस्तु को क्रमबद्ध करने के अनुकूलन कर सकते हैं- आपको ऑब्जेक्ट के सदस्यों के माध्यम से हर बार क्रमबद्ध करना होगा, और आपके पास ऑब्जेक्ट के आकार को पहले से जानने का कोई तरीका नहीं है (द्वारा गतिशील की परिभाषा)।

संबंधित मुद्दे