C# Language
बाइनरी सीरियल
खोज…
टिप्पणियों
बाइनरी क्रमांकन इंजन .NET फ्रेमवर्क का हिस्सा है, लेकिन यहां दिए गए उदाहरण C # के लिए विशिष्ट हैं। .NET फ्रेमवर्क में निर्मित अन्य सीरियलाइज़ेशन इंजनों की तुलना में, द्विआधारी धारावाहिक तेज और कुशल है और आमतौर पर इसे काम करने के लिए बहुत कम अतिरिक्त कोड की आवश्यकता होती है। हालाँकि, यह कोड परिवर्तन के प्रति कम सहिष्णु भी है; यानी, यदि आप किसी ऑब्जेक्ट को क्रमबद्ध करते हैं और फिर ऑब्जेक्ट की परिभाषा में थोड़ा बदलाव करते हैं, तो यह सही ढंग से डिस्क्राइब नहीं होगा।
किसी वस्तु को क्रमबद्ध बनाना
बाइनरी क्रमांकन के लिए एक संपूर्ण ऑब्जेक्ट को चिह्नित करने के लिए [Serializable]
विशेषता जोड़ें:
[Serializable]
public class Vector
{
public int X;
public int Y;
public int Z;
[NonSerialized]
public decimal DontSerializeThis;
[OptionalField]
public string Name;
}
जब तक हम स्पष्ट रूप से [NonSerialized]
विशेषता का उपयोग करते हुए सभी सदस्यों को [NonSerialized]
नहीं कर देंगे, तब तक उन्हें [NonSerialized]
। हमारे उदाहरण में, X
, Y
, Z
, और Name
सभी क्रमबद्ध हैं।
जब तक [NonSerialized]
या [OptionalField]
के साथ चिह्नित किए गए सभी सदस्यों को deserialization पर उपस्थित होना आवश्यक है। हमारे उदाहरण में, X
, Y
, और Z
सभी आवश्यक हैं और यदि धारा में मौजूद नहीं हैं, तो डिसररलाइजेशन विफल हो जाएगा। DontSerializeThis
यह हमेशा default(decimal)
(जो 0 है) पर सेट किया जाएगा। यदि Name
स्ट्रीम में मौजूद है, तो इसे उस मान पर सेट किया जाएगा, अन्यथा यह default(string)
(जो शून्य है) पर सेट हो जाएगा। [OptionalField]
का उद्देश्य थोड़ा संस्करण सहिष्णुता प्रदान करना है।
विशेषताओं के साथ क्रमबद्ध व्यवहार को नियंत्रित करना
यदि आप [NonSerialized]
विशेषता का उपयोग करते हैं, तो उस सदस्य का हमेशा [NonSerialized]
बाद इसका डिफ़ॉल्ट मान होगा (उदाहरण के लिए एक int
, string
लिए अशक्त, एक bool
लिए झूठा, आदि), वस्तु में किए गए किसी भी आरंभीकरण की परवाह किए बिना। (कंस्ट्रक्टर, घोषणा, आदि)। क्षतिपूर्ति करने के लिए, विशेषताओं [OnDeserializing]
(जिसे बस [OnDeserializing]
कहा जाता है) और [OnDeserialized]
(जिन्हें केवल [OnDeserialized]
कहा जाता है) अपने समकक्षों, [OnSerializing]
और [OnSerialized]
प्रदान की जाती हैं।
मान लें कि हम अपने वेक्टर में "रेटिंग" जोड़ना चाहते हैं और हम यह सुनिश्चित करना चाहते हैं कि मूल्य हमेशा 1 से शुरू होता है। जिस तरह से नीचे लिखा गया है, वह deserialized होने के बाद 0 होगा:
[Serializable]
public class Vector
{
public int X;
public int Y;
public int Z;
[NonSerialized]
public decimal Rating = 1M;
public Vector()
{
Rating = 1M;
}
public Vector(decimal initialRating)
{
Rating = initialRating;
}
}
इस समस्या को ठीक करने के लिए, हम इसे कक्षा में 1 पर सेट करने के लिए निम्न विधि जोड़ सकते हैं:
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
Rating = 1M;
}
या, यदि हम इसे परिकलित मान पर सेट करना चाहते हैं, तो हम इसके समाप्त होने की प्रतीक्षा कर सकते हैं और फिर इसे सेट कर सकते हैं:
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
Rating = 1 + ((X+Y+Z)/3);
}
इसी तरह, हम यह नियंत्रित कर सकते हैं कि [OnSerializing]
और [OnSerialized]
का उपयोग करके चीजें कैसे लिखी जाती हैं।
ISerializable लागू करके अधिक नियंत्रण जोड़ना
यह क्रमांकन पर अधिक नियंत्रण प्राप्त करेगा, कैसे प्रकार को बचाने और लोड करने के लिए
ISerializable इंटरफ़ेस लागू करें और संकलन करने के लिए एक खाली कंस्ट्रक्टर बनाएं
[Serializable]
public class Item : ISerializable
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public Item ()
{
}
protected Item (SerializationInfo info, StreamingContext context)
{
_name = (string)info.GetValue("_name", typeof(string));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("_name", _name, typeof(string));
}
}
डेटा क्रमांकन के लिए, आप वांछित नाम और वांछित प्रकार निर्दिष्ट कर सकते हैं
info.AddValue("_name", _name, typeof(string));
जब डेटा डिसेररलाइज़ किया जाता है, तो आप वांछित प्रकार को पढ़ सकेंगे
_name = (string)info.GetValue("_name", typeof(string));
सीरियलाइज़ेशन सरोगेट (ISerializationSurrogate को लागू करना)
क्रमबद्धता एक क्रमिक चयनकर्ता का चयन करती है जो एक वस्तु को क्रमबद्धता और दूसरे के विचलन का प्रदर्शन करने की अनुमति देती है
के रूप में अच्छी तरह से क्रमबद्ध या एक वर्ग है कि खुद ही serializable नहीं है deserialize करने की अनुमति देता है
ISerializationSurrogate इंटरफ़ेस लागू करें
public class ItemSurrogate : ISerializationSurrogate
{
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
var item = (Item)obj;
info.AddValue("_name", item.Name);
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
var item = (Item)obj;
item.Name = (string)info.GetValue("_name", typeof(string));
return item;
}
}
फिर आपको अपने IFormatter को SurrogateSelector को परिभाषित करने और आरंभ करने के लिए सरोगेट्स के बारे में बताना होगा और इसे अपने IFormatter को असाइन करना होगा।
var surrogateSelector = new SurrogateSelector();
surrogateSelector.AddSurrogate(typeof(Item), new StreamingContext(StreamingContextStates.All), new ItemSurrogate());
var binaryFormatter = new BinaryFormatter
{
SurrogateSelector = surrogateSelector
};
भले ही वह वर्ग क्रमबद्ध न हो।
//this class is not serializable
public class Item
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
पूरा समाधान
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinarySerializationExample
{
class Item
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
class ItemSurrogate : ISerializationSurrogate
{
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
var item = (Item)obj;
info.AddValue("_name", item.Name);
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
var item = (Item)obj;
item.Name = (string)info.GetValue("_name", typeof(string));
return item;
}
}
class Program
{
static void Main(string[] args)
{
var item = new Item
{
Name = "Orange"
};
var bytes = SerializeData(item);
var deserializedData = (Item)DeserializeData(bytes);
}
private static byte[] SerializeData(object obj)
{
var surrogateSelector = new SurrogateSelector();
surrogateSelector.AddSurrogate(typeof(Item), new StreamingContext(StreamingContextStates.All), new ItemSurrogate());
var binaryFormatter = new BinaryFormatter
{
SurrogateSelector = surrogateSelector
};
using (var memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, obj);
return memoryStream.ToArray();
}
}
private static object DeserializeData(byte[] bytes)
{
var surrogateSelector = new SurrogateSelector();
surrogateSelector.AddSurrogate(typeof(Item), new StreamingContext(StreamingContextStates.All), new ItemSurrogate());
var binaryFormatter = new BinaryFormatter
{
SurrogateSelector = surrogateSelector
};
using (var memoryStream = new MemoryStream(bytes))
return binaryFormatter.Deserialize(memoryStream);
}
}
}
सीरियलाइजेशन बाइंडर
बाइंडर आपको अपने आवेदन डोमेन में किस प्रकार के लोड किए जा रहे हैं, इसका निरीक्षण करने का अवसर देता है
SerializationBinder से विरासत में मिला एक वर्ग बनाएँ
class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
if (typeName.Equals("BinarySerializationExample.Item"))
return typeof(Item);
return null;
}
}
अब हम जांच कर सकते हैं कि इस प्रकार क्या लोड हो रहा है और इस आधार पर यह तय करना है कि हम वास्तव में क्या प्राप्त करना चाहते हैं
बाइंडर का उपयोग करने के लिए, आपको इसे बाइनरीफ़ॉर्मर में जोड़ना होगा।
object DeserializeData(byte[] bytes)
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Binder = new MyBinder();
using (var memoryStream = new MemoryStream(bytes))
return binaryFormatter.Deserialize(memoryStream);
}
पूरा समाधान
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace BinarySerializationExample
{
class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
if (typeName.Equals("BinarySerializationExample.Item"))
return typeof(Item);
return null;
}
}
[Serializable]
public class Item
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
class Program
{
static void Main(string[] args)
{
var item = new Item
{
Name = "Orange"
};
var bytes = SerializeData(item);
var deserializedData = (Item)DeserializeData(bytes);
}
private static byte[] SerializeData(object obj)
{
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, obj);
return memoryStream.ToArray();
}
}
private static object DeserializeData(byte[] bytes)
{
var binaryFormatter = new BinaryFormatter
{
Binder = new MyBinder()
};
using (var memoryStream = new MemoryStream(bytes))
return binaryFormatter.Deserialize(memoryStream);
}
}
}
पिछड़े अनुकूलता में कुछ गोटे
इस छोटे से उदाहरण से पता चलता है कि यदि आप इस बारे में पहले से ध्यान नहीं रखते हैं तो आप अपने कार्यक्रमों में पिछड़ी संगतता कैसे खो सकते हैं। और क्रमबद्धता प्रक्रिया के अधिक नियंत्रण पाने के तरीके
सबसे पहले, हम कार्यक्रम के पहले संस्करण का एक उदाहरण लिखेंगे:
संस्करण 1
[Serializable]
class Data
{
[OptionalField]
private int _version;
public int Version
{
get { return _version; }
set { _version = value; }
}
}
और अब, मान लेते हैं कि कार्यक्रम के दूसरे संस्करण में एक नया वर्ग जोड़ा गया है। और हमें इसे एक सरणी में संग्रहीत करने की आवश्यकता है।
अब कोड इस तरह दिखेगा:
संस्करण 2
[Serializable]
class NewItem
{
[OptionalField]
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
[Serializable]
class Data
{
[OptionalField]
private int _version;
public int Version
{
get { return _version; }
set { _version = value; }
}
[OptionalField]
private List<NewItem> _newItems;
public List<NewItem> NewItems
{
get { return _newItems; }
set { _newItems = value; }
}
}
और क्रमबद्ध और deserialize के लिए कोड
private static byte[] SerializeData(object obj)
{
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, obj);
return memoryStream.ToArray();
}
}
private static object DeserializeData(byte[] bytes)
{
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream(bytes))
return binaryFormatter.Deserialize(memoryStream);
}
और इसलिए, क्या होगा जब आप v2 के प्रोग्राम में डेटा को क्रमबद्ध करेंगे और v1 के कार्यक्रम में उन्हें डिसेर्बलाइज करने की कोशिश करेंगे?
आपको एक अपवाद मिलता है:
System.Runtime.Serialization.SerializationException was unhandled
Message=The ObjectManager found an invalid number of fixups. This usually indicates a problem in the Formatter.Source=mscorlib
StackTrace:
at System.Runtime.Serialization.ObjectManager.DoFixups()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at Microsoft.Samples.TestV1.Main(String[] args) in c:\Users\andrew\Documents\Visual Studio 2013\Projects\vts\CS\V1 Application\TestV1Part2\TestV1Part2.cs:line 29
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
क्यों?
ObjectManager में सरणियों के लिए निर्भरता को हल करने और संदर्भ और मान प्रकार के लिए एक अलग तर्क है। हमने नए संदर्भ प्रकार की एक सरणी जोड़ी है जो हमारी विधानसभा में अनुपस्थित है।
जब ObjectManager निर्भरता को हल करने का प्रयास करता है तो यह ग्राफ बनाता है। जब यह सरणी देखता है, तो इसे तुरंत ठीक नहीं किया जा सकता है, जिससे यह एक डमी संदर्भ बनाता है और फिर बाद में सरणी को ठीक करता है।
और चूंकि यह प्रकार विधानसभा में नहीं है और निर्भरता तय नहीं की जा सकती है। किसी कारण के लिए, यह फ़िक्सेस के लिए तत्वों की सूची से सरणी को नहीं हटाता है और अंत में, यह एक अपवाद "फेंकता है।
यह क्रमबद्धता की प्रक्रिया में कुछ 'गोटेक' हैं। किसी कारण से, यह केवल नए संदर्भ प्रकारों के सरणियों के लिए सही ढंग से काम नहीं करता है।
A Note:
Similar code will work correctly if you do not use arrays with new classes
और इसे ठीक करने और संगतता बनाए रखने का पहला तरीका?
- कक्षाओं के बजाय नई संरचनाओं का एक संग्रह का उपयोग करें या एक शब्दकोश (संभव कक्षाएं) का उपयोग करें, क्योंकि एक शब्दकोश यह कीवल्यूपेयर (यह संरचना) का एक संग्रह है
- यदि आप पुराने कोड को बदल नहीं सकते हैं, तो उपयोग करने योग्य है