Changing fields to properties in a Serializable class

by abutler 28. March 2011 15:47

Recently, I began preparing our code for code analysis using FxCop.  In beginning the project, I chose to enforce rule CA1051, part of the Microsoft Minimum Recommended Rules ruleset.  Seems pretty straightforward right?  I'll just have to change some fields to properties, maybe deal with some scoping issues, refactor some code, etc.

 

One of the problems I ran up against while enforcing this rule was in dealing with some of our serializable classes.  Say you have a class like this one:

 

[Serializable]
public class FieldsAreAwesome
{
	public int WhyNot;
}

 

This presents a bit of a problem, as changing the class to 

 

[Serializable]
public class FieldsAreAwesome
{
	public int WhyNot { get; set; }
}

 

will break serialization (properties are not serialized).  So there are a few options:

 

  1. Change the field scope to private, add a property to encapsulate then change all dependent code
  2. Implement custom serialization
  3. Just break it and hope the blame goes to someone else

 

#2 is not really a possibility, since the properties would have to have a different name and the amount of dependent code to be changed is not trivial in our codebase.

 

#1 turns out to be the only real option.  To do custom serialization, you have to implement ISerializable, like this:

 

[Serializable]
public class FieldsAreAwesome : ISerializable
{
	public int WhyNot { get; set; }

	#region ISerializable Members

	private FieldsAreAwesome(SerializationInfo info, StreamingContext context)
	{
		WhyNot = info.GetInt32("WhyNot");
	}

	public void GetObjectData(SerializationInfo info, StreamingContext context)
	{
		info.AddValue("WhyNot", WhyNot);
	}

	#endregion
}

 

The new constructor is required for deserialization, your code will fail at runtime if you don't have a constructor with the right arguments.

 

Say we had a serialized object from this class that was persisted somewhere.  This object is then deserialized using the new class above.  Since the names match, it will work.  Subsequent serializations / deserializations will also work using the new class.

 

Did I test this?  Yes.  Is there a better way of doing this?  Probably.  Will something break in production as a result of this? I certainly hope not.

 

Update:

Here's a better way to write the serialization constructor:

private FieldsAreAwesome(SerializationInfo info, StreamingContext context)
{
	foreach (SerializationEntry entry in info)
	{
		switch (entry.Name)
		{
			case "WhyNot":
				WhyNot = (int)entry.Value;
				break;
		}
	}
}
One thing to keep in mind is that once you commit to doing serialization yourself, you have to account for pretty much every scenario.  Checking for existing fields in the serialization info BEFORE trying to deserialize that field is a good idea.  I found this out the hard way.

Comments (1) -

8/1/2011 8:15:16 PM #

propertyslate

Excellent post.
Thanks a bunch for sharing this.

propertyslate United States | Reply

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


About the authors

We like to rock ICS Bank 2

Month List