When you serialize a class you convert its properties and values into a big string of xml, or a blob of binary data that uses less memory. The data will always contain the name of the class, xml namespaces and the names of the properties. We could make the data shorter if we substituted tokens for all these strings.
This code...
writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dic)
..will create an XmlDictionaryWriter that uses the XmlDictionary provided to perform this substitution. The problem is, that when I tried it, the binary data was the same length as when I did it without the dictionary -- the dictionary did nothing.
Digging into the reference source I discovered that the serializer will call TryLookup on the XmlDictionary to get the data required for the substitution:
public virtual bool TryLookup(XmlDictionaryString value, out XmlDictionaryString result) { if (value == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value")); if (value.Dictionary != this) { result = null; return false; } result = value; return true; }
The problem is that this was always true:
value.Dictionary != this....
Nearly every instance of XmlDictionaryString had it's own dictionary at the time of serialization. If you test the XmlDictionaryStirng objects just after creating them, then they have the expected dictionary - the one that you set. It must get changed during serialization.
I'm using VB.Net, so I simply re-implemented that class and skipped that check, see below.
The dictionary also useful to find out exactly which strings can be tokenized - just dump out value.value to get the parts of the xml that it wants to shorten.
Imports System.Collections.GenericImports System.XmlPublic Class MyDIckImplements IXmlDictionaryDim lookup As Dictionary(Of String, XmlDictionaryString)Dim strings() As XmlDictionaryStringDim nextId As IntegerSub New()lookup = New Dictionary(Of String, XmlDictionaryString)End SubPublic Sub New(capacity As Integer)lookup = New Dictionary(Of String, XmlDictionaryString)(capacity)strings = New XmlDictionaryString(capacity - 1) {}End SubPublic Function Add(value As String) As XmlDictionaryStringDim str As XmlDictionaryString = NothingIf lookup.TryGetValue(value, str) = False ThenIf strings Is Nothing Thenstrings = New XmlDictionaryString(3) {}ElseIf nextId = strings.Length ThenDim newSize = nextId * 2If newSize = 0 Then newSize = 4Array.Resize(strings, newSize)End Ifstr = New XmlDictionaryString(Me, value, nextId)strings(nextId) = strlookup.Add(value, str)nextId += 1End IfReturn strEnd FunctionPublic Function TryLookup(xds As XmlDictionaryString, ByRef result As XmlDictionaryString) As Boolean Implements IXmlDictionary.TryLookupReturn lookup.TryGetValue(xds.Value, result)End FunctionPublic Function TryLookup(key As Integer, ByRef result As XmlDictionaryString) As Boolean Implements IXmlDictionary.TryLookupIf key < 0 OrElse key >= nextId Thenresult = NothingReturn FalseEnd Ifresult = strings(key)Return TrueEnd FunctionPublic Function TryLookup(value As String, ByRef result As XmlDictionaryString) As Boolean Implements IXmlDictionary.TryLookupReturn lookup.TryGetValue(value, result)End FunctionEnd Class