|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionOn a project I was working on, we were in the need for serialization en mass. A lot of classes had to be serializable. Following are the requirements, the stages towards a solution, and a proposed solution. Design goals:
Using the codeSince this was my first date with serialization, I naturally went Googling to get a feeling for who I'm dating. It quickly seemed that serialization wasn't that hard. Many people suggested using the following wherever you need to serialize: Dim serializedObj As String
Dim serializer As New XmlSerializer(Me.GetType)
Dim writer As New StringWriter
serializer.Serialize(writer, Me)
serializedObj = writer.ToString()
Not so bad. You decorate your class with the Public Shared Function Serialize(obj as Object) As String
That looks OK. Let's have a look at the Public Shared Function Deserialize(xml As String, _
obj As Object) As Object
The client code would then look something like: ' serialize
Dim instance1 As New TestClass
Dim serializedInstance As String = _
SharedLib.Serialize(instance1)
' deserialize
Dim instance2 As New TestClass
instance2 = CType(SharedLib.DeSerialize(serializedInstance, _
instance2), TestClass)
At this point, I was in doubt. Should I stop here and accept something that I didn't feel very good about, or should I spend some more time to try to find a better solution? I had two problems with the above code. The client code was not intuitive enough, and there was still too much code needed to get the job done. From an object oriented perspective, I would much more like to have the methods on the class itself. I decided to look for something else. I hear you shout Generics, so here it comes, but with a twist. We'll leave the concept of utility functions all together. In a normal object model, you have objects that contain state and do actions. Most of us don't write Let's first look at how we want the calling code to look like, and then on how to implement our serialization to match that. ' serialize
Dim instance1 As New TestClass
Dim serializedInstance As String = instance1.Serialize()
' deserialize
Dim instance2 As TestClass1
instance2 = TestClass1.Deserialize(serializedInstance)
That's what I want the calling code to look like. Just to make things even between VB.NET and C#, I'll do the remaining part in C#. We want to add a Here is the base class implementation: [Serializable()]
public abstract class ContractBase<T>
{
/// Must have default constructor for xml serialization
public ContractBase()
{
}
/// Create an xml representation of this instance
public string Serialize()
{
XmlSerializer serializer = new XmlSerializer(this.GetType());
using (StringWriter stream = new StringWriter())
{
serializer.Serialize(stream, this);
stream.Flush();
return stream.ToString();
}
}
/// Creata a new instance from an xml string.
/// The client is responsible for deserialization of the correct type
public static T Deserialize(string xml)
{
if (string.IsNullOrEmpty(xml))
{
throw new ArgumentNullException("xml");
}
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader stream = new StringReader(xml))
{
try
{
return (T)serializer.Deserialize(stream);
}
catch (Exception ex)
{
// The serialization error messages are cryptic at best.
// Give a hint at what happened
throw new InvalidOperationException("Failed to " +
"create object from xml string", ex);
}
}
}
}
Here is a sample class, using the serialization base class we just wrote: [Serializable()]
public class TestClass : ContractBase< TestClass >
{
private string m_firstName;
public string FirstName
{
get
{
return m_firstName;
}
set
{
if (m_firstName == value)
return;
m_firstName = value;
}
}
Note that the The calling code now looks like what we wanted. //serialize
TestClass instance1 = new TestClass();
string serializedInstance = instance1.Serialize();
//deserialize
TestClass instance2;
instance2 = TestClass.Deserialize(serializedInstance);
See a better solution? Please let me know. You can also visit my blog. History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||