2010-08-27 23 views
8

के साथ .NET में पिछड़ा संगतता उपयोगकर्ता गेम प्रगति, गेम स्तर आदि को बचाने के लिए हम सी # गेम में बाइनरीफॉर्मेटर का उपयोग करते हैं। हम पीछे की संगतता की समस्या में भाग ले रहे हैं।बाइनरीफॉर्मेटर

उद्देश्य:

  • स्तर डिजाइनर अभियान (स्तर & नियम) बनाता है, हम कोड बदलने के लिए, अभियान अभी भी ठीक काम करना चाहिए। यह रिलीज से पहले विकास के दौरान हर रोज हो सकता है।
  • उपयोगकर्ता गेम बचाता है, हम एक गेम पैच जारी करते हैं, उपयोगकर्ता को अभी भी गेम
  • लोड करने में सक्षम होना चाहिए अदृश्य डेटा-रूपांतरण प्रक्रिया को काम करना चाहिए इससे कोई फर्क नहीं पड़ता कि दो संस्करण कितने दूर हैं। उदाहरण के लिए कोई उपयोगकर्ता हमारे पहले 5 मामूली अपडेट छोड़ सकता है और सीधे 6 वां प्राप्त कर सकता है। फिर भी, उनके सहेजे गए गेम अभी भी ठीक लोड होना चाहिए।

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

कुछ ऑब्जेक्ट ग्राफ जिन्हें हम क्रमबद्ध करते हैं, वे एक वर्ग में रूट होते हैं, कुछ दूसरों में। आगे संगतता की आवश्यकता नहीं है।

संभावित तोड़ने परिवर्तन (और क्या होता है जब हम पुराने संस्करण को क्रमानुसार और नए में deserialize):

  • जोड़ें फ़ील्ड (हो जाता है डिफ़ॉल्ट-प्रारंभ)
  • परिवर्तन क्षेत्र प्रकार (विफलता)
  • क्षेत्र का नाम बदलें (इसे हटाने और एक नया जोड़ने के बराबर)
  • फ़ील्ड और पीछे (एक नाम के बराबर) में संपत्ति बदलें
  • बैकिंग फ़ील्ड का उपयोग करने के लिए स्वत: पूरक संपत्ति बदलें एक नाम बदलने के लिए ivalent)
  • सुपरक्लास (वर्तमान कक्षा में अपने फ़ील्ड जोड़ने के बराबर) जोड़ें
  • एक फ़ील्ड को अलग-अलग व्याख्या करें (उदा। अब रेडियन में)
  • ISerializable लागू करने हम ISerializable तरीकों के बारे में हमारी कार्यान्वयन बदल सकते हैं प्रकार के लिए (उदाहरण के लिए वास्तव में कुछ बड़े प्रकार के लिए ISerializable कार्यान्वयन) के भीतर संपीड़न का उपयोग शुरू
  • एक वर्ग का नाम बदलें, डिग्री में था, एक enum मूल्य का नाम बदलने

    मैं के बारे में पढ़ा है

  • [वैकल्पिक फ़ील्ड (संस्करण जोड़ा गया)]
  • [ऑनडिसेरियलाइजिंग], [ऑनडिसेरियलाइज्ड], [ऑनसिरियलाइजिंग], [ऑनसिरियलाइज्ड]।
  • [NotSerialized]

मेरे वर्तमान समाधान:

  • हम संभव नॉन-ब्रेकिंग के रूप में कई परिवर्तन करें, OnDeserializing कॉलबैक की तरह सामान का उपयोग करके।
  • हम हर 2 सप्ताह में एक बार में परिवर्तन तोड़ने का शेड्यूल करते हैं, इसलिए आसपास रखने के लिए कम संगतता कोड है।
  • हम ब्रेकिंग परिवर्तन करने से पहले हर बार, हम सभी [Serializable] कक्षाओं का उपयोग करते हैं, जिन्हें हम पुराने क्लासवर्सन नामक नामस्थान/फ़ोल्डर में उपयोग करते हैं। VersionX (जहां एक्स अंतिम अंतिम के बाद अगला क्रम संख्या है)। हम यह भी करते हैं भले ही हम जल्द ही रिलीज नहीं करेंगे।
  • फ़ाइल लिखते समय, हम जो धारावाहिक करते हैं वह इस वर्ग का एक उदाहरण है: कक्षा SaveFileData {int संस्करण; ऑब्जेक्ट डेटा; }
  • जब फ़ाइल से पढ़ने, हम SaveFileData deserialize और यह एक सतत "अद्यतन" दिनचर्या कुछ इस तरह करता है को पारित:

for(int i = loadedData.version; i < CurrentVersion; i++) 
{ 
    // Update() takes an instance of OldVersions.VersionX.TheClass 
    // and returns an instance of OldVersions.VersionXPlus1.TheClass 
    loadedData.data = Update(loadedData.data, i); 
} 
  • सुविधा के लिए, अद्यतन() फ़ंक्शन, इसके कार्यान्वयन में, पुराने संस्करण से नए संस्करण के लिए जितना संभव हो उतना डेटा की प्रतिलिपि प्रतिबिंब का उपयोग करता है एक CopyOverlappingPart() फ़ंक्शन का उपयोग कर सकते हैं। इस प्रकार, अद्यतन() फ़ंक्शन केवल उन चीज़ों को संभाल सकता है जो वास्तव में बदलते हैं।

उस के साथ कुछ समस्याएं:

  • deserializer बल्कि वर्ग OldClassVersions.Version5.Foo की तुलना में वर्ग फू को deserializes - क्योंकि वर्ग फू क्या धारावाहिक है।
  • लगभग या परीक्षण असंभव डिबग
  • वर्गों का एक बहुत है, जो त्रुटि प्रवण, नाजुक और कष्टप्रद है के पुराने चारों ओर प्रतियां रखने के लिए की आवश्यकता है
  • मैं जब हम एक नाम बदलना चाहते हैं कि क्या करना है पता नहीं है वर्ग

यह एक बहुत ही आम समस्या होना चाहिए। लोग आमतौर पर इसे कैसे हल करते हैं?

+0

क्या आपने एक्सएमएल क्रमबद्धता पर स्विच करने का निर्णय लिया था या क्या आपको ऐसा करने का बेहतर तरीका मिला? एक्सएमएल क्रमबद्धता में ऐसी सीमाएं हैं जो मेरे कार्यक्रम के लिए काम नहीं करेगी, इसलिए मैं के.ऑफमैन के कुछ जोड़ों के साथ आपकी विधि का पालन करने की योजना बना रहा हूं। – i8abug

+0

@ i8abug: मैंने एक्सएमएल क्रमबद्धता में स्विच किया, हां। यदि आप मुझे उन परेशानियों को बताते हैं जो आपको परेशान कर रहे हैं, तो मैं आपको उनके बारे में बता सकता हूं, अगर मैं एक जानता हूं। –

+0

धन्यवाद! शुरुआत करने वालों के लिए, मुझे निजी और संरक्षित सदस्यों और सामान्य शब्दकोशों को क्रमबद्ध करने की आवश्यकता है। मैंने डेटाकंट्रैक सीरियलाइजेशन को देखने की कोशिश की लेकिन मुझे अज्ञात विरासत कक्षाओं (अन्य डेवलपर्स द्वारा लिखित) को क्रमबद्ध करने की आवश्यकता है और डेटाकंट्रैक्ट्स के साथ यह संभव नहीं है। बाइनरी क्रमबद्धता एकमात्र चीज है जो काम करती है। मैंने प्रोटोबफ-नेट भी चेक आउट किया लेकिन कुछ सीमाओं में भी भाग गया। जब आप एक्सएमएल क्रमबद्धता पर स्विच करते हैं, तो आपने सत्यापन को कैसे संभाला? क्या आपने अपने एक्सएमएल के प्रत्येक संस्करण के लिए एक विशिष्ट दुभाषिया बनाया है या आपने अभी भी कुछ ऐसा किया है जैसा आपने ऊपर वर्णित किया है? – i8abug

उत्तर

3

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

+0

बाइनरीसेरियलाइजेशन * फ़ील्ड जोड़ने/हटाने सहित छोटे बदलावों के लिए संस्करण-सहिष्णु है। "प्रबंधित करने में आसान" से आपका क्या मतलब है? एक्सएसएलटी वास्तव में एक महान समाधान की तरह लगता है। और नहीं, फ़ाइल का आकार और प्रदर्शन कोई मुद्दा नहीं है। –

+0

"आसान प्रबंधन" द्वारा मैं एक्सएमएल प्रारूप की मानव पठनीय प्रकृति और कक्षा संरचना से डेटा प्रतिनिधित्व के decoupling का जिक्र कर रहा हूँ (आप नियंत्रित कर सकते हैं कि धारावाहिक एक्सएमएल विशेषताएँ के माध्यम से कैसे दिख सकता है और संरचना नहीं है वास्तविक वर्ग दर्पण करने की आवश्यकता है) –

2

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

हमारे मामले में समस्या असेंबली वर्जन थी।

इस समस्या के लिए मैं एक SerializationBinder जो विधानसभाओं के वास्तविक विधानसभा संस्करण (सभी विधानसभाओं नई तैनाती पर एक नया संस्करण संख्या प्राप्त) Assembly.GetExecutingAssembly().GetName().Version साथ पढ़ता पैदा करते हैं।

ओवरराइड विधि BindToType प्रकार की जानकारी नई विधानसभा संस्करण के साथ बनाई गई है में

अक्रमांकन, इसका मतलब है कि सामान्य BinaryFormatter के माध्यम से

  • deserialize
  • हो जो deserialized किया जाना है सभी क्षेत्रों (खुद विशेषता के साथ एनोटेट)
  • से डेटा के साथ भरने वस्तु 'हाथ से' लागू किया गया है deserialized वस्तु

हमारे सभी डेटा के साथ काम करता है और तीन या चार रिलीज के बाद से काम करता है।