• 11
• 13
• 12
• 10
• 11
• entries
146
436
• views
198340

# On .Net Serialization, Part 7

422 views

Listing 1
public class NetworkFormatter {	public NetworkFormatter(Assembly sharedAssembly);	public void Serialize(Stream destinationStream, object graph);	internal Type[] GetSerializableTypes();	internal Dictionary GetTypeIdMap();	internal Type GetTypeFromId(int id);	internal int GetIdFromType(Type t);	private Dictionary typeIdMap;	private Type[] serializableTypes;	private Assembly sharedAssembly;}

We have some refactorings to do. Primarily, if you look over the NetworkFormatter class you will notice that it has a bunch of methods and fields that do not rightly belong to it. In fact, all of the internal methods, and the two fields that go with them, should really be in another class entirely. Simply put, it is not within the domain or responsibility of the NetworkFormatter class to enumerate the serializable types of an assembly, and then to assign them unique IDs. The refactoring should really be a two step process. The first involves creating a new class and moving the methods over to it, you would then rewrite the methods of the NetworkFormatter class in terms of this new class (it shall henceforth be called AssemblyTypeInformation). Then you would refactor the tests out so that they test the AssemblyTypeInformation class, removing the old tests from the NetworkFormatterTests class. However, I'm going to show both steps at the same time. Don't be fooled though, I did it in many smaller steps, it just takes too much space to go over every little step. Anyways, if you've been following my previous entries then you should already have an idea of the process to follow.

Listing 2
internal class AssemblyTypeInformation {	public AssemblyTypeInformation(Assembly sharedAssembly);	public Type GetTypeFromId(int id);	public int GetIdFromType(Type t) {		try {			return typeIdMap[t];		} catch (KeyNotFoundException) {			throw new SerializationException(				"Type is not from assembly: "				+ sharedAssembly.FullName			);		}	}	internal List GetSerializableTypes();	internal Dictionary GetTypeIdMap();	private Dictionary typeIdMap;	private List serializableTypes;	private Assembly sharedAssembly;}

public class NetworkFormatter {	public NetworkFormatter(Assembly sharedAssembly) {		typeInformationStore =			new AssemblyTypeInformation(sharedAssembly);	}	public void Serialize(Stream destinationStream, object graph);	private AssemblyTypeInformation typeInformationStore;}
So, first things first, writing the AssemblyTypeInformation class. As you can see in Listing 2, the interface is basically the same, in fact, it's pretty much a copy and paste. The constructor doesn't do anything particularily odd, it just calls GetSerializableTypes() and GetTypeIdMap() and store them in the fields, along with the Assembly. The two functions, GetTypeFromId() and GetIdFromType() are made part of our public interface, as they are what will be called by the serilization code. The two other methods, GetSerializableTypes() and GetTypeIdMap(), are left internal so that the test may access them, even though they will only be used internally by the AssemblyTypeInformation class. Looking over this we can also see that the NetworkFormatter no longer needs to maintain a reference to the assembly, so we can also remove that private field. Reducing the interface down to a constructor, the Serialize() method, and a single private field which is a reference to our AssemblyTypeInformation.

Listing 3
public void Serialize(Stream destinationStream, object graph) {	int id = typeInformationStore.GetIdFromType(graph.GetType());	BinaryWriter writer = new BinaryWriter(destinationStream);	writer.Write(id);}
Now that we have the IDs for our types generated, we can begin serializing our types out to the stream. First we will get the ID of the type, by the way I've modified GetIdFromType to throw a SerializationException should it not find the type, then we will write it out using a BinaryWriter. All happy with joy we remove the Ignore attribute from our TestSerialization() method, and run it, and it fails. looking at the error output we see: "System.Runtime.Serialization.SerializationException : Type (System.Object) is not from assembly: Kent.Serialization.Network, Version=1.0.1915.28857, Culture=neutral, PublicKeyToken=null". Hrm...seems we have a minor problem. Since Object is not a member of our assembly, it's not being enumerated, and hence not being assigned an ID. The simple fix is to manually add it in the AssemblyTypeInformation.GetSerializableObjects() method. Rebuilding and running our tests again we see a board of green lights. Of course, we have a lot more work to do still. For instance, we need to enumerate the fields of the type, and output them to the stream as well. We also will have to figure out how we wish to deal with nulls. But that's for next time.

## 1 Comment

Post the next one!!