2012-03-27 16 views
5

मैं बाइटरी धारावाहिक/deserialser लिख रहा हूं ताकि कई ऑब्जेक्ट प्रकारों को बाइट स्ट्रीम से/में परिवर्तित किया जा सके। ऑब्जेक्ट्स ब्लूटूथ या यूएसबी से जुड़े डिवाइस के लिए एपीआई कमांड और उनके संबंधित प्रतिक्रियाओं का प्रतिनिधित्व करते हैं। मैं स्ट्रीम को लिखने/पढ़ने के लिए BinaryWriter & BinaryReader का उपयोग कर रहा हूं।जेनेरिक बाइनरी रीडर

धारावाहिक आसान है। क्रमबद्ध करने के लिए उचित गुणों को एक विशेषता के साथ टैग किया गया है जो उस क्रम को निर्दिष्ट करता है जिसमें वे बाइट स्ट्रीम में लिखे जाते हैं। मैं BinaryWriter की सही Write(...) विधि चुनकर प्रतिबिंब और अधिभार संकल्प हैंडल का उपयोग करके गुणों के माध्यम से पुन: प्रयास करता हूं।

deserialiser काफी आसान नहीं है। फिर मैं विशेष प्रतिक्रिया वर्ग में उचित के माध्यम से पुन: प्रयास कर सकता हूं कि मैं उन प्रकारों को निर्धारित करने की उम्मीद कर रहा हूं जिन्हें स्ट्रीम से पढ़ने की आवश्यकता है। मुश्किल बिट मुझे पढ़ने के लिए BinaryReader पर कॉल करने के लिए सही विधि चुन रहा है। मैंने दो दृष्टिकोणों के बारे में सोचा है।

  1. एक बड़ा स्विच बयान है कि सही ReadXXXX() विधि प्रकार के आधार पर कॉल पढ़ने के लिए।
  2. स्ट्रिंग में आवश्यक विधि का नाम बनाने के लिए जिस प्रकार की आवश्यकता है, उसका नाम उपयोग करें, और फिर प्रतिबिंब का उपयोग करके विधि का आह्वान करें।

क्या कोई आसान तरीका है जिसके बारे में मैं सोच नहीं रहा हूं? यह सिर्फ एक शर्म की बात है कि आप अपने इच्छित प्रकार के आधार पर ओवरलोड रिज़ॉल्यूशन नहीं कर सकते हैं।

उत्तर

1

मैंने बाइनरी deserializer में विकल्प 1 (बड़ा स्विच स्टेटमेंट) का उपयोग किया है। एक क्लीनर तरीका हो सकता है कुछ की तरह:

interface IBinarySerializable 
{ 
    void Serialize(BinaryWriter toStream); 
    void Deserialize(BinaryReader fromStream); 
} 
फिर अपने आदेशों में

:

abstract class Command : IBinarySerializable 
{ 

} 

class SomeCommand : Command 
{ 
    public int Arg1 { get; set; } 

    public void Serialize(BinaryWriter toStream) 
    { 
     toStream.Write(Arg1); 
    } 

    public void Deserialize(BinaryReader fromStream) 
    { 
     Arg1 = fromStream.ReadInt32(); 
    } 
} 

और सामान्य क्रमबद्धता

{ 
    object result; 

    BinaryReader ...; 
    foreach (var propertyInfo in ...) 
    { 
     Func<BinaryReader, object> deserializer; 
     if (!supportedTypes.TryGetValue(propertyInfo.PropertyType, out deserializer)) 
     { 
      throw new NotSupportedException(string.Format(
       "Type of property '{0}' isn't supported ({1}).", propertyInfo.Name, propertyInfo.PropertyType)); 
     } 

     var deserialized = deserializer(reader); 
     propertyInfo.SetValue(result, deserialized, null); 
    } 
} 

private static Dictionary<Type, Func<BinaryReader, object>> supportedTypes = new Dictionary<Type, Func<BinaryReader, object>> 
{ 
    { typeof(int), br => br.ReadInt32() }, 
    // etc 
}; 

एक अन्य विकल्प आदेश वर्गों खुद को क्रमबद्धता करते हैं करने के लिए है विधियां:

void Serialize<T>(T obj) where T : IBinarySerializable 
{ 
    obj.Serialize(_stream); 
} 

T Deserialize<T>() where T : new(), IBinarySerializable 
{ 
    var result = new T(); 
    result.Deserialize(_stream); 
    return result; 
} 

लेकिन इस तरह आप कुछ कोड डुप्लिकेट कर सकते हैं। (दूसरी तरफ, व्युत्पन्न कक्षाएं आपके क्लासिक क्लास संस्करणों को सीरियलइज़/डेसराइलाइज के रूप में कॉल कर सकती हैं यदि यह आपके परिदृश्य में समझ में आता है, और यह अच्छी तरह से काम करता है।)

+0

वास्तव में कुछ अच्छे विकल्प, धन्यवाद। मैं पहले की ओर झुका रहा हूं क्योंकि यह मेरे वर्तमान कोड के साथ बेहतर फिट होगा। आपकी सहायता के लिए धन्यवाद. –

0

मुझे नहीं पता कि मैं पूरी तरह से समझ रहा हूं कि आप क्या करने की कोशिश कर रहे हैं । लेकिन यह बहुत अधिक ध्वनि है कि आप बाइनरीफॉर्मेटर और इसके सीरियलाइजेशन सरोगेट्स को .NET में नज़दीकी रूप से देखेंगे। बाइनरीफॉर्मेटर आपको आसानी से वस्तुओं को क्रमबद्ध और deserialize करने देता है और serialization सरोगेट्स आप अपने कस्टम serialization और deserialization तर्क जोड़ने और यह भी एक वस्तु को फिर से हटाने के लिए संभव बनाते हैं।

BinaryFormatter http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.aspx

ISerializationSurrogate http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate.aspx

SurrogateSelector http://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector.aspx

SerializationBinder http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder.aspx

:

यहाँ एक नजर डालें

आप यहां एक छोटा सा उदाहरण भी देख सकते हैं, जहां मेरे पास एक ऐसी विधि है जो किसी भी ऑब्जेक्ट को बेस 64 एन्कोडेड स्ट्रिंग में क्रमबद्ध कर सकती है, और फिर एक deserialize-method जो इस स्ट्रिंग को deserialize कर सकते हैं। मैं फॉर्मेटर को एक सीरियलाइजेशन बाइंडर भी जोड़ता हूं जो MyOldClass टाइप करने के लिए MyOldClass के क्रमबद्धता को रीमेप करता है और एक कस्टम ISerializationSurrogate भी जोड़ता है जो ऑब्जेक्ट में फ़ील्ड के मानों को एनर क्लास में जोड़ने से पहले संसाधित कर सकता है।

public class SerializeDeserializeExample { 
    public string Serialize(object objectToSerialize) { 
     using(var stream = new MemoryStream()) { 
     new BinaryFormatter().Serialize(stream, objectToSerialize); 
     return Convert.ToBase64String(stream.ToArray()); 
     } 
    } 

    public object Deserialize(string base64String) { 
     using(var stream = new MemoryStream(Convert.FromBase64String(base64String))) { 
     var formatter = new BinaryFormatter(); 
     var surrogateSelector = new SurrogateSelector(); 
     formatter.SurrogateSelector = surrogateSelector; 
     formatter.Binder = new DeserializationBinder(surrogateSelector); 
     return formatter.Deserialize(stream); 
     } 
    } 
} 


public class MyDeserializationBinder : SerializationBinder { 
    private readonly SurrogateSelector surrogateSelector; 

    public MyDeserializationBinder(SurrogateSelector surrogateSelector) { 
     this.surrogateSelector = surrogateSelector; 
    } 

    public override Type BindToType(string assemblyName, string typeName) { 
     if(typeName.Equals("MyOldClass", StringComparison.InvariantCultureIgnoreCase)) { 
     return RemapToType(); 
     } 
     return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName)); 
    } 

    private Type RemapToType() { 
     var remapToType = typeof(MyNewClass); 
     surrogateSelector.AddSurrogate(remapToType, 
           new StreamingContext(StreamingContextStates.All), 
           new MyCustomDeserializationSurrogate()); 
     return remapToType; 
    } 
} 

public sealed class MyCustomDeserializationSurrogate : ISerializationSurrogate { 

    public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context) { 
     throw new NotImplementedException(); 
    } 

    public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { 
     var objectType = obj.GetType(); 
     var fields = GetFields(objectType); 
     foreach(var fieldInfo in fields) { 
     var fieldValue = info.GetValue(fieldInfo.Name, fieldInfo.FieldType); 
     fieldValue = DoSomeProcessing(fieldValue); 
     fieldInfo.SetValue(obj, fieldValue); 
     } 
     return obj; 
    } 

    private static IEnumerable<FieldInfo> GetFields(Type objectType) { 
     return objectType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | 
          BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); 
    } 

    private static object DoSomeProcessing(object value){ 
     //Do some processing with the object 
    } 
} 
+0

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

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