• 10
• 10
• 12
• 12
• 14
• entries
146
436
• views
198359

# On .Net Serialization, Part 8

555 views

I want some feedback, and don't be afraid to ask questions. I'm considering taking slightly larger steps now, considering that you should be getting the idea of how to properly use refactoring and testing. What I was thinking (and we'll try it out in this journal entry) is that I would move on to discussing topics without mentioning the refactorings or tests that take place. They will be assumed to have taken place. This is not to say that I won't mention certain refactorings that we need to do. Quite the opposite, it will give me more space to actually discuss specific refactorings, instead of the minor ones that come between the meat. I'm going to skip ahead a bit, and discuss some new components we're going to build into the AssemblyTypeInformation class.

I also wanted to briefly mention a particularly nice plugin you can get for Visual Studio, from TestDriven.NET. It's a very cool plugin that allows you to run NUnit tests (along with many other testing frameworks) from within Visual Studio. Any failures, warnings, or ignored tests will show up in the ToDo list of Visual Studio. Makes your life much more enjoyable, as it's one less application you need to keep running in the background.

One of the things our serializer is going to have to do is be able to serizialize the fields within a type. In order to do this, we will need to enumerate the fields, and then serialize each one out. The problem is that there is no specific order in which the fields are guaranteed to be returned in. Which means that we must force our own order onto the fields. However, this is one of those operations that we don't need to repeat over and over again, as the fields will not change for a type, so it would be economical to store the fields of a type in a sorted order already, and then just query for that array. TO do this we will extend the AssemblyTypeInformation class to include a new private field, and a few new functions.

Listing 1
internal class AssemblyTypeInformation {	public AssemblyTypeInformation(Assembly sharedAssembly)	public Type GetTypeFromId(int id)	public int GetIdFromType(Type t)	internal List GetSerializableTypes()	internal Dictionary GetTypeIdMap()}

As you may recall, our AssemblyTypeInformation class looked much like listing 1, albeit with a few more fields and some code too. To this class we are going to add a Dictionary field. This will store a sorted array of the serializable fields in each type, using the type as the key to retrieve the array. The array will be populated at construction time using a new member function, GetTypeFieldsMap(). GetTypeFieldsMap() will loop through each type and call GetSerializableFields(), which is another member function we will write, on the type and store the result in the dictionary. Finally we will write a GetFieldsFromType() public method, which will lookup the array in the dictionary and return that array.

Listing 2
internal Dictionary GetTypeFieldsMap() {	Dictionary typeFieldsMap = new Dictionary();	List types = GetSerializableTypes();	foreach (Type t in types) {		typeFieldsMap.Add(t, GetSerializableFields(t));	}	return typeFieldsMap;}internal FieldInfo[] GetSerializableFields(Type t) {	FieldInfo[] fields = t.GetFields(BindingFlags.Public |		BindingFlags.NonPublic |		BindingFlags.Instance);	List serializableFields = new List();	foreach (FieldInfo f in fields) {		if (!f.IsNotSerialized && f.FieldType.IsSerializable) {			serializableFields.Add(f);		}	}	serializableFields.Sort(delegate(FieldInfo x, FieldInfo y) {		return x.Name.CompareTo(y.Name);	});	return serializableFields.ToArray();}
As we can see in listing 2, enumerating the fields of all of the types is fairly simple. First we just get a list of all of the serializable types. Then we loop through each type and ask for all of the public and non-public (which will include internal, protected, and private fields) instance fields. This will then return an array of said fields. We then loop through each field, test that the field isn't marked as being [NonSerializable] and also that the type of the field is serializable. If it is serializable, then we add it to the list. Finally we sort the list using an anonymous comparison delegate, which will sort it by name. Finally, we return the array of fields. Which is then stored in the dictionary along with the associated type. If the field has no serializable types, then an empty array will be returned, and stored, which is what we want since this will allow us to write code that doesn't have to worry about null arrays. You should, of course, write some tests to verify that the fields are being sorted and stored in the array, but that is left as an exercise for the reader. You should also add the new field that I mentioned above, and a call in the constructor to set it using the GetTypeFieldsMap() method.

Listing 3
public FieldInfo[] GetFieldsFromType(Type t) {	try {		return typeFieldsMap[t];	} catch (KeyNotFoundException) {		throw new SerializationException(			"Type (" + t + ") is not from assembly: "			+ sharedAssembly.FullName);	}}
Finally we need to write a lookup method to expose this information to our serializer. This is rather simply done, as shown in listing 3. With this done we can now proceed to writing some more serialization code, but I will leave that for the next entry. An additional note: You should really make the GetFieldsFromType() method throw a serialization exception if it doesn't find the type within the dictionary, as shown in listing 3.

## 1 Comment

Very informative! Nice link, by the way.