Serialization with .NET - Serializing Only Some Internal Data
(Page 3 of 4 )
The Serializable attribute, however, marks the entire class as being serializable. In our Person example, all of the internal data in bob is serialized. While this is fine in some cases, it may be undesirable in others. It may not make sense to serialize some internal data, and some internal data may contain sensitive material. For example, consider this class:
using System;
[Serializable]
public class User
{
private string name;
private DateTime sessionStartTime;
public User(string name)
{
this.name = name;
sessionStartTime = DateTime.Now;
}
public string Name
{
get
{
return name;
}
}
public DateTime SessionStartTime
{
get
{
return sessionStartTime;
}
}
}
The class represents a computer user and contains a private field of type DateTime which represents the time that the user logged in. When an instance of User is initialized, sessionStartTime is set to the current time. However, it doesn't make sense to store this field because when the user logs off (which we'll represent by saving the class), the time is no longer valid. In order to prevent .NET from serializing a piece of data, it must be marked with the NonSerialized attribute:
[Serializable]
public class User
{
...
[NonSerialized]
private DateTime sessionStartTime;
...
}
Now, when a User object is serialized, sessionStartTime won't be included. Let's try this out:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
class UserSerialization
{
public static void Main(string[] args)
{
// Create a User
User charles = new User("Charles");
Console.WriteLine("{0}, logged on since {1}.", charles.Name, charles.SessionStartTime);
// Serialize the User
FileStream myStream = File.Create("charles");
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(myStream, charles);
// Deserialize the User
myStream.Position = 0;
charles = (User)formatter.Deserialize(myStream);
myStream.Close();
Console.WriteLine("{0}, logged on since {1}.", charles.Name, charles.SessionStartTime);
}
}
If we run the above code, we can see that sessionStartTime isn't serialized, just as we specified. However, something happens as a side effect, as can be seen from the output:
Charles, logged on since 8/2/2007 8:42:03 PM.
Charles, logged on since 1/1/0001 12:00:00 AM.
Since sessionStartTime is not serialized, .NET is forced to find a new value for it upon deserialization. It initializes it to the default value, which is evident above. Of course, this is not what we want. Instead, we want it to contain the date and time when the object was deserialized. To remedy this, .NET offers several attributes that can be applied to methods, such as OnDeserializing. Methods marked with OnDeserializing will be called during the deserialization process. We can add such a method to Person that will give sessionStartTime the proper value. Here's how it's done:
[Serializable]
public class User
{
...
[OnDeserializing]
internal void OnDeserializing(StreamingContext context)
{
sessionStartTime = DateTime.Now;
}
}
As you can see, the method has no return type, and it accepts one parameter, a StreamingContext structure. This structure contains information about the serialization process, but here, we can safely ignore it. Any method taking advantage of OnDeserializing must have no return type and must accept a StreamingContext, just like our method.
Now, Person behaves as we want it to:
Charles, logged on since 8/2/2007 8:51:30 PM.
Charles, logged on since 8/2/2007 8:51:30 PM.
Next: Other Attributes >>
More .NET Articles
More By Peyton McCullough