added units tests for TextReader ReadLine() and ReadToEnd()
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectWriter.cs
index b61e7fc3b9a495286f762f413afb8fcb59684899..f7f71db0fdaf8209d809e9b7a9d18efe6368ef22 100644 (file)
-// ObjectWriter.cs\r
-//\r
-// Author:\r
-//   Lluis Sanchez Gual (lluis@ideary.com)\r
-//\r
-// (C) 2003 Lluis Sanchez Gual\r
-\r
-//\r
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)\r
-//\r
-// Permission is hereby granted, free of charge, to any person obtaining\r
-// a copy of this software and associated documentation files (the\r
-// "Software"), to deal in the Software without restriction, including\r
-// without limitation the rights to use, copy, modify, merge, publish,\r
-// distribute, sublicense, and/or sell copies of the Software, and to\r
-// permit persons to whom the Software is furnished to do so, subject to\r
-// the following conditions:\r
-// \r
-// The above copyright notice and this permission notice shall be\r
-// included in all copies or substantial portions of the Software.\r
-// \r
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-//\r
-\r
-using System;\r
-using System.IO;\r
-using System.Collections;\r
-using System.Runtime.Serialization;\r
-using System.Runtime.Remoting.Messaging;\r
-using System.Reflection;\r
-using System.Globalization;\r
-\r
-namespace System.Runtime.Serialization.Formatters.Binary\r
-{\r
-       abstract class TypeMetadata\r
-       {\r
-               public string TypeAssemblyName;\r
-               public string InstanceTypeName;\r
-               \r
-               public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);\r
-               public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes);\r
-               public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);\r
-               \r
-               public virtual bool IsCompatible (TypeMetadata other)\r
-               {\r
-                       return true;\r
-               }\r
-               \r
-               public abstract bool RequiresTypes { get; }\r
-       }\r
-       \r
-       abstract class ClrTypeMetadata: TypeMetadata\r
-       {\r
-               public Type InstanceType;\r
-\r
-               public ClrTypeMetadata (Type instanceType)\r
-               {\r
-                       InstanceType = instanceType;\r
-                       InstanceTypeName = instanceType.FullName;\r
-                       TypeAssemblyName = instanceType.Assembly.FullName;\r
-               }\r
-               \r
-               public override bool RequiresTypes {\r
-                       get { return false; }\r
-               }\r
-       }\r
-       \r
-       class SerializableTypeMetadata: TypeMetadata\r
-       {\r
-               Type[] types;\r
-               string[] names;\r
-               \r
-               public SerializableTypeMetadata (Type itype, SerializationInfo info)\r
-               {\r
-                       types = new Type [info.MemberCount];\r
-                       names = new string [info.MemberCount];\r
-\r
-                       SerializationInfoEnumerator e = info.GetEnumerator ();\r
-\r
-                       int n = 0;\r
-                       while (e.MoveNext ())\r
-                       {\r
-                               types[n] = e.ObjectType;\r
-                               names[n] = e.Name;\r
-                               n++;\r
-                       }\r
-\r
-                       TypeAssemblyName = info.AssemblyName;\r
-                       InstanceTypeName = info.FullTypeName;\r
-               }\r
-               \r
-               public override bool IsCompatible (TypeMetadata other)\r
-               {\r
-                       if (!(other is SerializableTypeMetadata)) return false;\r
-                       \r
-                       SerializableTypeMetadata tm = (SerializableTypeMetadata)other;\r
-                       if (types.Length != tm.types.Length) return false;\r
-                       if (TypeAssemblyName != tm.TypeAssemblyName) return false;\r
-                       if (InstanceTypeName != tm.InstanceTypeName) return false;\r
-                       for (int n=0; n<types.Length; n++)\r
-                       {\r
-                               if (types[n] != tm.types[n]) return false;\r
-                               if (names[n] != tm.names[n]) return false;\r
-                       }\r
-                       return true;\r
-               }\r
-               \r
-               public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)\r
-               {\r
-                       foreach (Type mtype in types)\r
-                       {\r
-                               Type type = mtype;\r
-                               while (type.IsArray) \r
-                                       type = type.GetElementType();\r
-                                       \r
-                               ow.WriteAssembly (writer, type.Assembly);\r
-                       }\r
-               }\r
-               \r
-               public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)\r
-               {\r
-                       writer.Write (types.Length);\r
-\r
-                       // Names of fields\r
-                       foreach (string name in names)\r
-                               writer.Write (name);\r
-\r
-                       // Types of fields\r
-                       foreach (Type type in types)\r
-                               ObjectWriter.WriteTypeCode (writer, type);\r
-\r
-                       // Type specs of fields\r
-                       foreach (Type type in types)\r
-                               ow.WriteTypeSpec (writer, type);\r
-               }\r
-               \r
-               public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)\r
-               {\r
-                       SerializationInfo info = (SerializationInfo) data;\r
-                       SerializationInfoEnumerator e = info.GetEnumerator ();\r
-\r
-                       while (e.MoveNext ())\r
-                               ow.WriteValue (writer, e.ObjectType, e.Value);\r
-               }\r
-               \r
-               public override bool RequiresTypes {\r
-                       get { return true; }\r
-               }\r
-       }\r
-       \r
-       class MemberTypeMetadata: ClrTypeMetadata\r
-       {\r
-               MemberInfo[] members;\r
-               \r
-               public MemberTypeMetadata (Type type, StreamingContext context): base (type)\r
-               {\r
-                       members = FormatterServices.GetSerializableMembers (type, context);\r
-               }\r
-\r
-               public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)\r
-               {\r
-                       foreach (FieldInfo field in members)\r
-                       {\r
-                               Type type = field.FieldType;\r
-                               while (type.IsArray) \r
-                                       type = type.GetElementType();\r
-                                       \r
-                               ow.WriteAssembly (writer, type.Assembly);\r
-                       }\r
-               }\r
-               \r
-               public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)\r
-               {\r
-                       writer.Write (members.Length);\r
-\r
-                       // Names of fields\r
-                       foreach (FieldInfo field in members)\r
-                               writer.Write (field.Name);\r
-\r
-                       if (writeTypes) {\r
-                               // Types of fields\r
-                               foreach (FieldInfo field in members)\r
-                                       ObjectWriter.WriteTypeCode (writer, field.FieldType);\r
-       \r
-                               // Type specs of fields\r
-                               foreach (FieldInfo field in members)\r
-                                       ow.WriteTypeSpec (writer, field.FieldType);\r
-                       }\r
-               }\r
-               \r
-               public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)\r
-               {\r
-                       object[] values = FormatterServices.GetObjectData (data, members);\r
-                       for (int n=0; n<values.Length; n++)\r
-                               ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);\r
-               }\r
-       }\r
-       \r
-       internal class ObjectWriter\r
-       {\r
-               ObjectIDGenerator _idGenerator = new ObjectIDGenerator();\r
-               Hashtable _cachedMetadata = new Hashtable();\r
-               Queue _pendingObjects = new Queue();\r
-               Hashtable _assemblyCache = new Hashtable();\r
-               \r
-               // Type metadata that can be shared with all serializers\r
-               static Hashtable _cachedTypes = new Hashtable();\r
-\r
-               internal static Assembly CorlibAssembly = typeof(string).Assembly;\r
-               internal static string CorlibAssemblyName = typeof(string).Assembly.FullName;\r
-\r
-               ISurrogateSelector _surrogateSelector;\r
-               StreamingContext _context;\r
-               FormatterAssemblyStyle _assemblyFormat;\r
-               FormatterTypeStyle _typeFormat;\r
-               byte[] arrayBuffer;\r
-               int ArrayBufferLength = 4096;\r
-#if NET_2_0
-               SerializationObjectManager _manager;
+// ObjectWriter.cs
+//
+// Author:
+//   Lluis Sanchez Gual (lluis@ideary.com)
+//
+// (C) 2003 Lluis Sanchez Gual
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Runtime.Serialization;
+using System.Runtime.Remoting.Messaging;
+using System.Reflection;
+using System.Globalization;
+
+namespace System.Runtime.Serialization.Formatters.Binary
+{
+       abstract class TypeMetadata
+       {
+               public string TypeAssemblyName;
+               public string InstanceTypeName;
+               
+               public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);
+               public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes);
+               public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);
+               
+               public virtual bool IsCompatible (TypeMetadata other)
+               {
+                       return true;
+               }
+
+#if NET_4_0
+               public void BindToName (string assemblyName, string typeName)
+               {
+                       if (assemblyName != null)
+                               TypeAssemblyName = assemblyName;
+                       if (typeName != null)
+                               InstanceTypeName = typeName;
+               }
 #endif
-               \r
-               class MetadataReference\r
-               {\r
-                       public TypeMetadata Metadata;\r
-                       public long ObjectID;\r
-                       \r
-                       public MetadataReference (TypeMetadata metadata, long id)\r
-                       {\r
-                               Metadata = metadata;\r
-                               ObjectID = id;\r
-                       }\r
-               }\r
-               \r
-               public ObjectWriter (ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)\r
-               {\r
-                       _surrogateSelector = surrogateSelector;\r
-                       _context = context;\r
-                       _assemblyFormat = assemblyFormat;\r
-                       _typeFormat = typeFormat;\r
-#if NET_2_0
-                       _manager = new SerializationObjectManager (context);
+               
+               public abstract bool RequiresTypes { get; }
+       }
+       
+       abstract class ClrTypeMetadata: TypeMetadata
+       {
+               public Type InstanceType;
+
+               public ClrTypeMetadata (Type instanceType)
+               {
+                       InstanceType = instanceType;
+                       InstanceTypeName = instanceType.FullName;
+                       TypeAssemblyName = instanceType.Assembly.FullName;
+               }
+               
+               public override bool RequiresTypes {
+                       get { return false; }
+               }
+       }
+       
+       class SerializableTypeMetadata: TypeMetadata
+       {
+               Type[] types;
+               string[] names;
+               
+               public SerializableTypeMetadata (Type itype, SerializationInfo info)
+               {
+                       types = new Type [info.MemberCount];
+                       names = new string [info.MemberCount];
+
+                       SerializationInfoEnumerator e = info.GetEnumerator ();
+
+                       int n = 0;
+                       while (e.MoveNext ())
+                       {
+                               types[n] = e.ObjectType;
+                               names[n] = e.Name;
+                               n++;
+                       }
+
+                       TypeAssemblyName = info.AssemblyName;
+                       InstanceTypeName = info.FullTypeName;
+               }
+               
+               public override bool IsCompatible (TypeMetadata other)
+               {
+                       if (!(other is SerializableTypeMetadata)) return false;
+                       
+                       SerializableTypeMetadata tm = (SerializableTypeMetadata)other;
+                       if (types.Length != tm.types.Length) return false;
+                       if (TypeAssemblyName != tm.TypeAssemblyName) return false;
+                       if (InstanceTypeName != tm.InstanceTypeName) return false;
+                       for (int n=0; n<types.Length; n++)
+                       {
+                               if (types[n] != tm.types[n]) return false;
+                               if (names[n] != tm.names[n]) return false;
+                       }
+                       return true;
+               }
+               
+               public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
+               {
+                       foreach (Type mtype in types)
+                       {
+                               Type type = mtype;
+                               while (type.IsArray) 
+                                       type = type.GetElementType();
+                                       
+                               ow.WriteAssembly (writer, type.Assembly);
+                       }
+               }
+               
+               public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
+               {
+                       writer.Write (types.Length);
+
+                       // Names of fields
+                       foreach (string name in names)
+                               writer.Write (name);
+
+                       // Types of fields
+                       foreach (Type type in types)
+                               ObjectWriter.WriteTypeCode (writer, type);
+
+                       // Type specs of fields
+                       foreach (Type type in types)
+                               ow.WriteTypeSpec (writer, type);
+               }
+               
+               public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
+               {
+                       SerializationInfo info = (SerializationInfo) data;
+                       SerializationInfoEnumerator e = info.GetEnumerator ();
+
+                       while (e.MoveNext ())
+                               ow.WriteValue (writer, e.ObjectType, e.Value);
+               }
+               
+               public override bool RequiresTypes {
+                       get { return true; }
+               }
+       }
+       
+       class MemberTypeMetadata: ClrTypeMetadata
+       {
+               MemberInfo[] members;
+               
+               public MemberTypeMetadata (Type type, StreamingContext context): base (type)
+               {
+                       members = FormatterServices.GetSerializableMembers (type, context);
+               }
+
+               public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
+               {
+                       foreach (FieldInfo field in members)
+                       {
+                               Type type = field.FieldType;
+                               while (type.IsArray) 
+                                       type = type.GetElementType();
+                                       
+                               ow.WriteAssembly (writer, type.Assembly);
+                       }
+               }
+               
+               public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
+               {
+                       writer.Write (members.Length);
+
+                       // Names of fields
+                       foreach (FieldInfo field in members)
+                               writer.Write (field.Name);
+
+                       if (writeTypes) {
+                               // Types of fields
+                               foreach (FieldInfo field in members)
+                                       ObjectWriter.WriteTypeCode (writer, field.FieldType);
+       
+                               // Type specs of fields
+                               foreach (FieldInfo field in members)
+                                       ow.WriteTypeSpec (writer, field.FieldType);
+                       }
+               }
+               
+               public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
+               {
+                       object[] values = FormatterServices.GetObjectData (data, members);
+                       for (int n=0; n<values.Length; n++)
+                               ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);
+               }
+       }
+       
+       internal class ObjectWriter
+       {
+               ObjectIDGenerator _idGenerator = new ObjectIDGenerator();
+               Hashtable _cachedMetadata = new Hashtable();
+               Queue _pendingObjects = new Queue();
+               Hashtable _assemblyCache = new Hashtable();
+               
+               // Type metadata that can be shared with all serializers
+               static Hashtable _cachedTypes = new Hashtable();
+
+               internal static Assembly CorlibAssembly = typeof(string).Assembly;
+               internal static string CorlibAssemblyName = typeof(string).Assembly.FullName;
+
+               ISurrogateSelector _surrogateSelector;
+               StreamingContext _context;
+               FormatterAssemblyStyle _assemblyFormat;
+               FormatterTypeStyle _typeFormat;
+#if NET_4_0
+               SerializationBinder _binder;
+#endif
+               byte[] arrayBuffer;
+               int ArrayBufferLength = 4096;
+               SerializationObjectManager _manager;
+               
+               class MetadataReference
+               {
+                       public TypeMetadata Metadata;
+                       public long ObjectID;
+                       
+                       public MetadataReference (TypeMetadata metadata, long id)
+                       {
+                               Metadata = metadata;
+                               ObjectID = id;
+                       }
+               }
+               
+               public ObjectWriter (BinaryFormatter formatter)
+               {
+                       _surrogateSelector = formatter.SurrogateSelector;
+                       _context = formatter.Context;
+                       _assemblyFormat = formatter.AssemblyFormat;
+                       _typeFormat = formatter.TypeFormat;
+                       _manager = new SerializationObjectManager (formatter.Context);
+#if NET_4_0
+                       _binder = formatter.Binder;
 #endif
-               }\r
-\r
-               public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)\r
-               {\r
-                       _pendingObjects.Clear();\r
-                       if (headers != null) QueueObject (headers);\r
-                       QueueObject (obj);\r
-                       WriteQueuedObjects (writer);\r
-                       WriteSerializationEnd (writer);\r
-#if NET_2_0
+               }
+
+               public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)
+               {
+                       _pendingObjects.Clear();
+                       if (headers != null) QueueObject (headers);
+                       QueueObject (obj);
+                       WriteQueuedObjects (writer);
+                       WriteSerializationEnd (writer);
                        _manager.RaiseOnSerializedEvent ();
+               }
+
+               public void QueueObject (object obj)
+               {
+                       _pendingObjects.Enqueue (obj);
+               }
+
+               public void WriteQueuedObjects (BinaryWriter writer)
+               {
+                       while (_pendingObjects.Count > 0)
+                               WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);
+               }
+
+               public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)
+               {
+                       bool firstTime;
+                       long id;
+
+                       // If the object is a value type (not boxed) then there is no need
+                       // to register it in the id generator, because it won't have other
+                       // references to it
+
+                       if (isValueObject) id = _idGenerator.NextId;
+                       else id = _idGenerator.GetId (obj, out firstTime);
+
+                       if (obj is string) {
+                               WriteString (writer, id, (string)obj);
+                       }
+                       else if (obj is Array) {
+                               WriteArray (writer, id, (Array)obj);
+                       }
+                       else
+                               WriteObject (writer, id, obj);
+               }
+
+               public static void WriteSerializationEnd (BinaryWriter writer)
+               {
+                       writer.Write ((byte) BinaryElement.End);
+               }
+
+               private void WriteObject (BinaryWriter writer, long id, object obj)
+               {
+                       object data;
+                       TypeMetadata metadata;
+
+                       GetObjectData (obj, out metadata, out data);
+                       MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceTypeName];
+
+                       if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))
+                       {
+                               // An object of the same type has already been serialized
+                               // It is not necessary to write again type metadata
+
+                               writer.Write ((byte) BinaryElement.RefTypeObject);
+                               writer.Write ((int)id);
+
+                               writer.Write ((int)metadataReference.ObjectID);
+                               metadata.WriteObjectData (this, writer, data);
+                               return;
+                       }
+
+                       if (metadataReference == null)
+                       {
+                               metadataReference = new MetadataReference (metadata, id);
+                               _cachedMetadata [metadata.InstanceTypeName] = metadataReference;
+                       }
+                       
+                       bool writeTypes = metadata.RequiresTypes || _typeFormat == FormatterTypeStyle.TypesAlways;
+
+                       BinaryElement objectTag;
+
+                       int assemblyId;
+                       if (metadata.TypeAssemblyName == CorlibAssemblyName)
+                       {
+                               // A corlib type
+                               objectTag = writeTypes ? BinaryElement.RuntimeObject : BinaryElement.UntypedRuntimeObject;
+                               assemblyId = -1;
+                       }
+                       else
+                       {
+                               objectTag = writeTypes ? BinaryElement.ExternalObject : BinaryElement.UntypedExternalObject;
+                               assemblyId = WriteAssemblyName (writer, metadata.TypeAssemblyName);
+                       }
+
+                       // Registers the assemblies needed for each field
+                       // If there are assemblies that where not registered before this object,
+                       // write them now
+
+                       metadata.WriteAssemblies (this, writer);
+
+                       // Writes the object
+
+                       writer.Write ((byte) objectTag);
+                       writer.Write ((int)id);
+                       writer.Write (metadata.InstanceTypeName);
+                       
+                       metadata.WriteTypeData (this, writer, writeTypes);
+                       if (assemblyId != -1) writer.Write (assemblyId);
+                       
+                       metadata.WriteObjectData (this, writer, data);
+               }
+
+               private void GetObjectData (object obj, out TypeMetadata metadata, out object data)
+               {
+                       Type instanceType = obj.GetType();
+#if NET_4_0
+                       string binderAssemblyName = null;
+                       string binderTypeName = null;
+                       if (_binder != null)
+                               _binder.BindToName (instanceType, out binderAssemblyName, out binderTypeName);
+#endif
+                       // Check if the formatter has a surrogate selector, if it does, 
+                       // check if the surrogate selector handles objects of the given type. 
+
+                       if (_surrogateSelector != null)
+                       {
+                               ISurrogateSelector selector;
+                               ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);
+                               if (surrogate != null)
+                               {
+                                       SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
+                                       surrogate.GetObjectData (obj, info, _context);
+                                       metadata = new SerializableTypeMetadata (instanceType, info);
+#if NET_4_0
+                                       if (_binder != null)
+                                               metadata.BindToName (binderAssemblyName, binderTypeName);
 #endif
-               }\r
-\r
-               public void QueueObject (object obj)\r
-               {\r
-                       _pendingObjects.Enqueue (obj);\r
-               }\r
-\r
-               public void WriteQueuedObjects (BinaryWriter writer)\r
-               {\r
-                       while (_pendingObjects.Count > 0)\r
-                               WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);\r
-               }\r
-\r
-               public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)\r
-               {\r
-                       bool firstTime;\r
-                       long id;\r
-\r
-                       // If the object is a value type (not boxed) then there is no need\r
-                       // to register it in the id generator, because it won't have other\r
-                       // references to it\r
-\r
-                       if (isValueObject) id = _idGenerator.NextId;\r
-                       else id = _idGenerator.GetId (obj, out firstTime);\r
-\r
-                       if (obj is string) {\r
-                               WriteString (writer, id, (string)obj);\r
-                       }\r
-                       else if (obj is Array) {\r
-                               WriteArray (writer, id, (Array)obj);\r
-                       }\r
-                       else\r
-                               WriteObject (writer, id, obj);\r
-               }\r
-\r
-               public static void WriteSerializationEnd (BinaryWriter writer)\r
-               {\r
-                       writer.Write ((byte) BinaryElement.End);\r
-               }\r
-\r
-               private void WriteObject (BinaryWriter writer, long id, object obj)\r
-               {\r
-                       object data;\r
-                       TypeMetadata metadata;\r
-\r
-                       GetObjectData (obj, out metadata, out data);\r
-                       MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceTypeName];\r
-\r
-                       if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))\r
-                       {\r
-                               // An object of the same type has already been serialized\r
-                               // It is not necessary to write again type metadata\r
-\r
-                               writer.Write ((byte) BinaryElement.RefTypeObject);\r
-                               writer.Write ((int)id);\r
-\r
-                               writer.Write ((int)metadataReference.ObjectID);\r
-                               metadata.WriteObjectData (this, writer, data);\r
-                               return;\r
-                       }\r
-\r
-                       if (metadataReference == null)\r
-                       {\r
-                               metadataReference = new MetadataReference (metadata, id);\r
-                               _cachedMetadata [metadata.InstanceTypeName] = metadataReference;\r
-                       }\r
-                       \r
-                       bool writeTypes = metadata.RequiresTypes || _typeFormat == FormatterTypeStyle.TypesAlways;\r
-\r
-                       BinaryElement objectTag;\r
-\r
-                       int assemblyId;\r
-                       if (metadata.TypeAssemblyName == CorlibAssemblyName)\r
-                       {\r
-                               // A corlib type\r
-                               objectTag = writeTypes ? BinaryElement.RuntimeObject : BinaryElement.UntypedRuntimeObject;\r
-                               assemblyId = -1;\r
-                       }\r
-                       else\r
-                       {\r
-                               objectTag = writeTypes ? BinaryElement.ExternalObject : BinaryElement.UntypedExternalObject;\r
-                               assemblyId = WriteAssemblyName (writer, metadata.TypeAssemblyName);\r
-                       }\r
-\r
-                       // Registers the assemblies needed for each field\r
-                       // If there are assemblies that where not registered before this object,\r
-                       // write them now\r
-\r
-                       metadata.WriteAssemblies (this, writer);\r
-\r
-                       // Writes the object\r
-\r
-                       writer.Write ((byte) objectTag);\r
-                       writer.Write ((int)id);\r
-                       writer.Write (metadata.InstanceTypeName);\r
-                       \r
-                       metadata.WriteTypeData (this, writer, writeTypes);\r
-                       if (assemblyId != -1) writer.Write (assemblyId);\r
-                       \r
-                       metadata.WriteObjectData (this, writer, data);\r
-               }\r
-\r
-               private void GetObjectData (object obj, out TypeMetadata metadata, out object data)\r
-               {\r
-                       Type instanceType = obj.GetType();\r
-\r
-                       // Check if the formatter has a surrogate selector, if it does, \r
-                       // check if the surrogate selector handles objects of the given type. \r
-\r
-                       if (_surrogateSelector != null)\r
-                       {\r
-                               ISurrogateSelector selector;\r
-                               ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);\r
-                               if (surrogate != null)\r
-                               {\r
-                                       SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());\r
-                                       surrogate.GetObjectData (obj, info, _context);\r
-                                       metadata = new SerializableTypeMetadata (instanceType, info);\r
-                                       data = info;\r
-                                       return;\r
-                               }\r
-                       }\r
-\r
-                       // Check if the object is marked with the Serializable attribute\r
-\r
-                       BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);\r
-\r
-#if NET_2_0
+
+                                       data = info;
+                                       return;
+                               }
+                       }
+
+                       // Check if the object is marked with the Serializable attribute
+
+                       BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);
+
                        _manager.RegisterObject (obj);
+
+                       ISerializable ser = obj as ISerializable;
+
+                       if (ser != null) 
+                       {
+                               SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
+                               ser.GetObjectData (info, _context);
+                               metadata = new SerializableTypeMetadata (instanceType, info);
+#if NET_4_0
+                               if (_binder != null)
+                                       metadata.BindToName (binderAssemblyName, binderTypeName);
+#endif
+
+                               data = info;
+                       } 
+                       else 
+                       {
+                               data = obj;
+                               if (_context.Context != null)
+                               {
+                                       // Don't cache metadata info when the Context property is not null sice
+                                       // we can't control the number of possible contexts in this case
+                                       metadata = new MemberTypeMetadata (instanceType, _context);
+#if NET_4_0
+                                       if (_binder != null)
+                                               metadata.BindToName (binderAssemblyName, binderTypeName);
+#endif
+
+                                       return;
+                               }
+                               
+                               Hashtable typesTable;
+                               bool isNew = false;
+                               lock (_cachedTypes) {
+                                       typesTable = (Hashtable) _cachedTypes [_context.State];
+                                       if (typesTable == null) {
+                                               typesTable = new Hashtable ();
+                                               _cachedTypes [_context.State] = typesTable;
+                                               isNew = true;
+                                       }
+                               }
+
+                               metadata = null;
+                               lock (typesTable) {
+                                       if (!isNew) {
+                                               metadata = (TypeMetadata) typesTable [instanceType];
+                                       }
+
+                                       if (metadata == null) {
+                                               metadata = CreateMemberTypeMetadata (instanceType);
+#if NET_4_0
+                                               if (_binder != null)
+                                                       metadata.BindToName (binderAssemblyName, binderTypeName);
 #endif
+                                       }
+
+                                       typesTable [instanceType] = metadata;
+                               }
+                       }
+               }
+               
+               TypeMetadata CreateMemberTypeMetadata (Type type)
+               {
+                       if (!BinaryCommon.UseReflectionSerialization) {
+                               Type metaType = CodeGenerator.GenerateMetadataType (type, _context);
+                               return (TypeMetadata) Activator.CreateInstance (metaType);
+                       }
+                       else
+                               return new MemberTypeMetadata (type, _context);
+               }
+
+               private void WriteArray (BinaryWriter writer, long id, Array array)
+               {
+                       // There are 4 ways of serializing arrays:
+                       // The element GenericArray (7) can be used for all arrays.
+                       // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
+                       // arrays of primitive types
+                       // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
+                       // The element ArrayOfString (17) can be used for single-dimensional string arrays
+
+                       Type elementType = array.GetType().GetElementType();
+
+                       if (elementType == typeof (object) && array.Rank == 1) {
+                               WriteObjectArray (writer, id, array);
+                       }
+                       else if (elementType == typeof (string) && array.Rank == 1) {
+                               WriteStringArray (writer, id, array);
+                       }
+                       else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {
+                               WritePrimitiveTypeArray (writer, id, array);
+                       }
+                       else
+                               WriteGenericArray (writer, id, array);
+               }
+
+               private void WriteGenericArray (BinaryWriter writer, long id, Array array)
+               {
+                       Type elementType = array.GetType().GetElementType();
+
+                       // Registers and writes the assembly of the array element type if needed
+
+                       if (!elementType.IsArray)
+                               WriteAssembly (writer, elementType.Assembly);
+
+                       // Writes the array
+
+                       writer.Write ((byte) BinaryElement.GenericArray);
+                       writer.Write ((int)id);
+                       
+                       // Write the structure of the array
+
+                       if (elementType.IsArray) 
+                               writer.Write ((byte) ArrayStructure.Jagged);
+                       else if (array.Rank == 1)
+                               writer.Write ((byte) ArrayStructure.SingleDimensional);
+                       else
+                               writer.Write ((byte) ArrayStructure.MultiDimensional);
+
+                       // Write the number of dimensions and the length
+                       // of each dimension
+
+                       writer.Write (array.Rank);
+                       for (int n=0; n<array.Rank; n++)
+                               writer.Write (array.GetUpperBound (n) + 1);
+
+                       // Writes the type
+                       WriteTypeCode (writer, elementType);
+                       WriteTypeSpec (writer, elementType);
+
+                       // Writes the values. For single-dimension array, a special tag is used
+                       // to represent multiple consecutive null values. I don't know why this
+                       // optimization is not used for multidimensional arrays.
+
+                       if (array.Rank == 1 && !elementType.IsValueType)
+                       {
+                               WriteSingleDimensionArrayElements (writer, array, elementType);
+                       }
+                       else
+                       {
+                               foreach (object item in array)
+                                       WriteValue (writer, elementType, item);
+                       }
+               }
+
+               private void WriteObjectArray (BinaryWriter writer, long id, Array array)
+               {
+                       writer.Write ((byte) BinaryElement.ArrayOfObject);
+                       writer.Write ((int)id);
+                       writer.Write (array.Length);    // Single dimension. Just write the length
+                       WriteSingleDimensionArrayElements (writer, array, typeof (object));
+               }
+
+               private void WriteStringArray (BinaryWriter writer, long id, Array array)
+               {
+                       writer.Write ((byte) BinaryElement.ArrayOfString);
+                       writer.Write ((int)id);
+                       writer.Write (array.Length);    // Single dimension. Just write the length
+                       WriteSingleDimensionArrayElements (writer, array, typeof (string));
+               }
+
+               private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)
+               {
+                       writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);
+                       writer.Write ((int)id);
+                       writer.Write (array.Length);    // Single dimension. Just write the length
+
+                       Type elementType = array.GetType().GetElementType();
+                       WriteTypeSpec (writer, elementType);
+
+                       switch (Type.GetTypeCode (elementType))
+                       {
+                               case TypeCode.Boolean:
+                                       foreach (bool item in (bool[]) array)
+                                               writer.Write (item);
+                                       break;
+
+                               case TypeCode.Byte:
+                                       writer.Write ((byte[]) array);
+                                       break;
+
+                               case TypeCode.Char:
+                                       writer.Write ((char[]) array);
+                                       break;
+
+                               case TypeCode.DateTime: 
+                                       foreach (DateTime item in (DateTime[]) array)
+                                               writer.Write (item.ToBinary ());
+                                       break;
+
+                               case TypeCode.Decimal:
+                                       foreach (decimal item in (decimal[]) array)
+                                               writer.Write (item);
+                                       break;
+
+                               case TypeCode.Double:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 8);
+                                       else
+                                               foreach (double item in (double[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.Int16:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 2);
+                                       else
+                                               foreach (short item in (short[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.Int32:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 4);
+                                       else
+                                               foreach (int item in (int[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.Int64:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 8);
+                                       else
+                                               foreach (long item in (long[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.SByte:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 1);
+                                       else
+                                               foreach (sbyte item in (sbyte[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.Single:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 4);
+                                       else
+                                               foreach (float item in (float[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.UInt16:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 2);
+                                       else
+                                               foreach (ushort item in (ushort[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.UInt32:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 4);
+                                       else
+                                               foreach (uint item in (uint[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.UInt64:
+                                       if (array.Length > 2)
+                                               BlockWrite (writer, array, 8);
+                                       else
+                                               foreach (ulong item in (ulong[]) array)
+                                                       writer.Write (item);
+                                       break;
+
+                               case TypeCode.String:
+                                       foreach (string item in (string[]) array)
+                                               writer.Write (item);
+                                       break;
+
+                               default:
+                                       if (elementType == typeof (TimeSpan)) {
+                                               foreach (TimeSpan item in (TimeSpan[]) array)
+                                                       writer.Write (item.Ticks);
+                                       }
+                                       else
+                                               throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
+                                       break;
+                       }                       
+               }
+               
+               private void BlockWrite (BinaryWriter writer, Array array, int dataSize)
+               {
+                       int totalSize = Buffer.ByteLength (array);
+                       
+                       if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
+                               arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
+                       
+                       int pos = 0;
+                       while (totalSize > 0) {
+                               int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
+                               Buffer.BlockCopy (array, pos, arrayBuffer, 0, size);
+                               
+                               if (!BitConverter.IsLittleEndian && dataSize > 1)
+                                       BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
+                               
+                               writer.Write (arrayBuffer, 0, size);
+                               totalSize -= size;
+                               pos += size;
+                       }
+               }
+
+               private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)
+               {
+                       int numNulls = 0;
+                       foreach (object val in array)
+                       {
+                               if (val != null && numNulls > 0)
+                               {
+                                       WriteNullFiller (writer, numNulls);
+                                       WriteValue (writer, elementType, val);
+                                       numNulls = 0;
+                               }
+                               else if (val == null)
+                                       numNulls++;
+                               else
+                                       WriteValue (writer, elementType, val);
+                       }
+                       if (numNulls > 0)
+                               WriteNullFiller (writer, numNulls);
+               }
+
+               private void WriteNullFiller (BinaryWriter writer, int numNulls)
+               {
+                       if (numNulls == 1) {
+                               writer.Write ((byte) BinaryElement.NullValue);
+                       }
+                       else if (numNulls == 2) {
+                               writer.Write ((byte) BinaryElement.NullValue);
+                               writer.Write ((byte) BinaryElement.NullValue);
+                       }
+                       else if (numNulls <= byte.MaxValue) {
+                               writer.Write ((byte) BinaryElement.ArrayFiller8b);
+                               writer.Write ((byte) numNulls);
+                       }
+                       else {
+                               writer.Write ((byte) BinaryElement.ArrayFiller32b);
+                               writer.Write (numNulls);
+                       }
+               }
+
+               private void WriteObjectReference (BinaryWriter writer, long id)
+               {
+
+                       writer.Write ((byte) BinaryElement.ObjectReference);
+                       writer.Write ((int)id);
+               }
+
+               public void WriteValue (BinaryWriter writer, Type valueType, object val)
+               {
+                       if (val == null) 
+                       {
+                               BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);
+                               writer.Write ((byte) BinaryElement.NullValue);
+                       }
+                       else if (BinaryCommon.IsPrimitive(val.GetType()))
+                       {
+                               if (!BinaryCommon.IsPrimitive(valueType))
+                               {
+                                       // It is a boxed primitive type value
+                                       writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);
+                                       WriteTypeSpec (writer, val.GetType());
+                               }
+                               WritePrimitiveValue (writer, val);
+                       }
+                       else if (valueType.IsValueType)
+                       {
+                               // Value types are written embedded in the containing object
+                               WriteObjectInstance (writer, val, true);
+                       }
+                       else if (val is string)
+                       {
+                               // Strings are written embedded, unless already registered
+                               bool firstTime;
+                               long id = _idGenerator.GetId (val, out firstTime);
+
+                               if (firstTime) WriteObjectInstance (writer, val, false);
+                               else WriteObjectReference (writer, id);
+                       }                       
+                       else
+                       {
+                               // It is a reference type. Write a forward reference and queue the
+                               // object to the pending object list (unless already written).
+
+                               bool firstTime;
+                               long id = _idGenerator.GetId (val, out firstTime);
+
+                               if (firstTime) _pendingObjects.Enqueue (val);
+                               WriteObjectReference (writer, id);
+                       }
+               }
+               
+               private void WriteString (BinaryWriter writer, long id, string str)
+               {
+                       writer.Write ((byte) BinaryElement.String);
+                       writer.Write ((int)id);
+                       writer.Write (str);
+               }
+
+               public int WriteAssembly (BinaryWriter writer, Assembly assembly)
+               {
+                       return WriteAssemblyName (writer, assembly.FullName);
+               }
+               
+               public int WriteAssemblyName (BinaryWriter writer, string assembly)
+               {
+                       if (assembly == ObjectWriter.CorlibAssemblyName) return -1;
+                       
+                       bool firstTime;
+                       int id = RegisterAssembly (assembly, out firstTime);
+                       if (!firstTime) return id;
+                                       
+                       writer.Write ((byte) BinaryElement.Assembly);
+                       writer.Write (id);
+                       if (_assemblyFormat == FormatterAssemblyStyle.Full)
+                               writer.Write (assembly);
+                       else {
+                               int i = assembly.IndexOf (',');
+                               if (i != -1) assembly = assembly.Substring (0, i);
+                               writer.Write (assembly);
+                       }
+                               
+                       return id;
+               }
+
+               public int GetAssemblyId (Assembly assembly)
+               {
+                       return GetAssemblyNameId (assembly.FullName);
+               }
+               
+               public int GetAssemblyNameId (string assembly)
+               {
+                       return (int)_assemblyCache[assembly];
+               }
+
+               private int RegisterAssembly (string assembly, out bool firstTime)
+               {
+                       if (_assemblyCache.ContainsKey (assembly))
+                       {
+                               firstTime = false;
+                               return (int)_assemblyCache[assembly];
+                       }
+                       else
+                       {
+                               int id = (int)_idGenerator.GetId (0, out firstTime);
+                               _assemblyCache.Add (assembly, id);
+                               return id;
+                       }
+               }
+
+               public static void WritePrimitiveValue (BinaryWriter writer, object value)
+               {
+                       Type type = value.GetType();
+
+                       switch (Type.GetTypeCode (type))
+                       {
+                               case TypeCode.Boolean:
+                                       writer.Write ((bool)value);
+                                       break;
+
+                               case TypeCode.Byte:
+                                       writer.Write ((byte) value);
+                                       break;
+
+                               case TypeCode.Char:
+                                       writer.Write ((char) value);
+                                       break;
+
+                               case TypeCode.DateTime: 
+                                       writer.Write ( ((DateTime)value).ToBinary ());
+                                       break;
+
+                               case TypeCode.Decimal:
+                                       writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));
+                                       break;
+
+                               case TypeCode.Double:
+                                       writer.Write ((double) value);
+                                       break;
+
+                               case TypeCode.Int16:
+                                       writer.Write ((short) value);
+                                       break;
+
+                               case TypeCode.Int32:
+                                       writer.Write ((int) value);
+                                       break;
+
+                               case TypeCode.Int64:
+                                       writer.Write ((long) value);
+                                       break;
+
+                               case TypeCode.SByte:
+                                       writer.Write ((sbyte) value);
+                                       break;
+
+                               case TypeCode.Single:
+                                       writer.Write ((float) value);
+                                       break;
+
+                               case TypeCode.UInt16:
+                                       writer.Write ((ushort) value);
+                                       break;
+
+                               case TypeCode.UInt32:
+                                       writer.Write ((uint) value);
+                                       break;
+
+                               case TypeCode.UInt64:
+                                       writer.Write ((ulong) value);
+                                       break;
+
+                               case TypeCode.String:
+                                       writer.Write ((string) value);
+                                       break;
+
+                               default:
+                                       if (type == typeof (TimeSpan))
+                                               writer.Write (((TimeSpan)value).Ticks);
+                                       else
+                                               throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);
+                                       break;
+                       }
+               }
+
+               public static void WriteTypeCode (BinaryWriter writer, Type type)
+               {
+                       writer.Write ((byte) GetTypeTag (type));
+               }
+
+               public static TypeTag GetTypeTag (Type type)
+               {
+                       if (type == typeof (string)) {
+                               return TypeTag.String;
+                       }
+                       else if (BinaryCommon.IsPrimitive (type)) {
+                               return TypeTag.PrimitiveType;
+                       }
+                       else if (type == typeof (object)) {
+                               return TypeTag.ObjectType;
+                       }
+                       else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {
+                               return TypeTag.ArrayOfObject; 
+                       }
+                       else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){
+                               return TypeTag.ArrayOfString;
+                       }
+                       else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {
+                               return TypeTag.ArrayOfPrimitiveType;
+                       }
+                       else if (type.Assembly == CorlibAssembly) {
+                               return TypeTag.RuntimeType;
+                       }
+                       else
+                               return TypeTag.GenericType;
+               }
+
+               public void WriteTypeSpec (BinaryWriter writer, Type type)
+               {
+                       // WARNING Keep in sync with EmitWriteTypeSpec
+                       
+                       switch (GetTypeTag (type))
+                       {
+                               case TypeTag.PrimitiveType:
+                                       writer.Write (BinaryCommon.GetTypeCode (type));
+                                       break;
+
+                               case TypeTag.RuntimeType:
+                                       string fullName = type.FullName;
+                                       // Map System.MonoType to MS.NET's System.RuntimeType,
+                                       // when called in remoting context.
+                                       // Note that this code does not need to be in sync with
+                                       // EmitWriteTypeSpec because serializing a MethodCall
+                                       // won't trigger the CodeGenerator.
+                                       if (_context.State == StreamingContextStates.Remoting)
+                                               if (type == typeof (System.MonoType))
+                                                       fullName =  "System.RuntimeType";
+                                               else if (type == typeof (System.MonoType[]))
+                                                       fullName =  "System.RuntimeType[]";
+                                       writer.Write (fullName);
+                                       break;
+
+                               case TypeTag.GenericType:
+                                       writer.Write (type.FullName);
+                                       writer.Write ((int)GetAssemblyId (type.Assembly));
+                                       break;
+
+                               case TypeTag.ArrayOfPrimitiveType:
+                                       writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));
+                                       break;
 
-                       ISerializable ser = obj as ISerializable;\r
-\r
-                       if (ser != null) \r
-                       {\r
-                               SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());\r
-                               ser.GetObjectData (info, _context);\r
-                               metadata = new SerializableTypeMetadata (instanceType, info);\r
-                               data = info;\r
-                       } \r
-                       else \r
-                       {\r
-                               data = obj;\r
-                               if (_context.Context != null)\r
-                               {\r
-                                       // Don't cache metadata info when the Context property is not null sice\r
-                                       // we can't control the number of possible contexts in this case\r
-                                       metadata = new MemberTypeMetadata (instanceType, _context);\r
-                                       return;\r
-                               }\r
-                               \r
-                               Hashtable typesTable;\r
-                               bool isNew = false;\r
-                               lock (_cachedTypes) {\r
-                                       typesTable = (Hashtable) _cachedTypes [_context.State];\r
-                                       if (typesTable == null) {\r
-                                               typesTable = new Hashtable ();\r
-                                               _cachedTypes [_context.State] = typesTable;\r
-                                               isNew = true;\r
-                                       }\r
-                               }\r
-\r
-                               metadata = null;\r
-                               lock (typesTable) {\r
-                                       if (!isNew) {\r
-                                               metadata = (TypeMetadata) typesTable [instanceType];\r
-                                       }\r
-\r
-                                       if (metadata == null) {\r
-                                               metadata = CreateMemberTypeMetadata (instanceType);\r
-                                       }\r
-\r
-                                       typesTable [instanceType] = metadata;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               TypeMetadata CreateMemberTypeMetadata (Type type)\r
-               {\r
-                       if (!BinaryCommon.UseReflectionSerialization) {\r
-                               Type metaType = CodeGenerator.GenerateMetadataType (type, _context);\r
-                               return (TypeMetadata) Activator.CreateInstance (metaType);\r
-                       }\r
-                       else\r
-                               return new MemberTypeMetadata (type, _context);\r
-               }\r
-\r
-               private void WriteArray (BinaryWriter writer, long id, Array array)\r
-               {\r
-                       // There are 4 ways of serializing arrays:\r
-                       // The element GenericArray (7) can be used for all arrays.\r
-                       // The element ArrayOfPrimitiveType (15) can be used for single-dimensional\r
-                       // arrays of primitive types\r
-                       // The element ArrayOfObject (16) can be used for single-dimensional Object arrays\r
-                       // The element ArrayOfString (17) can be used for single-dimensional string arrays\r
-\r
-                       Type elementType = array.GetType().GetElementType();\r
-\r
-                       if (elementType == typeof (object) && array.Rank == 1) {\r
-                               WriteObjectArray (writer, id, array);\r
-                       }\r
-                       else if (elementType == typeof (string) && array.Rank == 1) {\r
-                               WriteStringArray (writer, id, array);\r
-                       }\r
-                       else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {\r
-                               WritePrimitiveTypeArray (writer, id, array);\r
-                       }\r
-                       else\r
-                               WriteGenericArray (writer, id, array);\r
-               }\r
-\r
-               private void WriteGenericArray (BinaryWriter writer, long id, Array array)\r
-               {\r
-                       Type elementType = array.GetType().GetElementType();\r
-\r
-                       // Registers and writes the assembly of the array element type if needed\r
-\r
-                       if (!elementType.IsArray)\r
-                               WriteAssembly (writer, elementType.Assembly);\r
-\r
-                       // Writes the array\r
-\r
-                       writer.Write ((byte) BinaryElement.GenericArray);\r
-                       writer.Write ((int)id);\r
-                       \r
-                       // Write the structure of the array\r
-\r
-                       if (elementType.IsArray) \r
-                               writer.Write ((byte) ArrayStructure.Jagged);\r
-                       else if (array.Rank == 1)\r
-                               writer.Write ((byte) ArrayStructure.SingleDimensional);\r
-                       else\r
-                               writer.Write ((byte) ArrayStructure.MultiDimensional);\r
-\r
-                       // Write the number of dimensions and the length\r
-                       // of each dimension\r
-\r
-                       writer.Write (array.Rank);\r
-                       for (int n=0; n<array.Rank; n++)\r
-                               writer.Write (array.GetUpperBound (n) + 1);\r
-\r
-                       // Writes the type\r
-                       WriteTypeCode (writer, elementType);\r
-                       WriteTypeSpec (writer, elementType);\r
-\r
-                       // Writes the values. For single-dimension array, a special tag is used\r
-                       // to represent multiple consecutive null values. I don't know why this\r
-                       // optimization is not used for multidimensional arrays.\r
-\r
-                       if (array.Rank == 1 && !elementType.IsValueType)\r
-                       {\r
-                               WriteSingleDimensionArrayElements (writer, array, elementType);\r
-                       }\r
-                       else\r
-                       {\r
-                               foreach (object item in array)\r
-                                       WriteValue (writer, elementType, item);\r
-                       }\r
-               }\r
-\r
-               private void WriteObjectArray (BinaryWriter writer, long id, Array array)\r
-               {\r
-                       writer.Write ((byte) BinaryElement.ArrayOfObject);\r
-                       writer.Write ((int)id);\r
-                       writer.Write (array.Length);    // Single dimension. Just write the length\r
-                       WriteSingleDimensionArrayElements (writer, array, typeof (object));\r
-               }\r
-\r
-               private void WriteStringArray (BinaryWriter writer, long id, Array array)\r
-               {\r
-                       writer.Write ((byte) BinaryElement.ArrayOfString);\r
-                       writer.Write ((int)id);\r
-                       writer.Write (array.Length);    // Single dimension. Just write the length\r
-                       WriteSingleDimensionArrayElements (writer, array, typeof (string));\r
-               }\r
-\r
-               private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)\r
-               {\r
-                       writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);\r
-                       writer.Write ((int)id);\r
-                       writer.Write (array.Length);    // Single dimension. Just write the length\r
-\r
-                       Type elementType = array.GetType().GetElementType();\r
-                       WriteTypeSpec (writer, elementType);\r
-\r
-                       switch (Type.GetTypeCode (elementType))\r
-                       {\r
-                               case TypeCode.Boolean:\r
-                                       foreach (bool item in (bool[]) array)\r
-                                               writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.Byte:\r
-                                       writer.Write ((byte[]) array);\r
-                                       break;\r
-\r
-                               case TypeCode.Char:\r
-                                       writer.Write ((char[]) array);\r
-                                       break;\r
-\r
-                               case TypeCode.DateTime: \r
-                                       foreach (DateTime item in (DateTime[]) array) {\r
-                                               ulong val = (ulong) item.Ticks;\r
-#if NET_2_0\r
-                                               val |= ((ulong) item.Kind) << 62;\r
-#endif\r
-                                               writer.Write (val);\r
-                                       }\r
-                                       break;\r
-\r
-                               case TypeCode.Decimal:\r
-                                       foreach (decimal item in (decimal[]) array)\r
-                                               writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.Double:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 8);\r
-                                       else\r
-                                               foreach (double item in (double[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.Int16:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 2);\r
-                                       else\r
-                                               foreach (short item in (short[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.Int32:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 4);\r
-                                       else\r
-                                               foreach (int item in (int[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.Int64:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 8);\r
-                                       else\r
-                                               foreach (long item in (long[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.SByte:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 1);\r
-                                       else\r
-                                               foreach (sbyte item in (sbyte[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.Single:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 4);\r
-                                       else\r
-                                               foreach (float item in (float[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.UInt16:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 2);\r
-                                       else\r
-                                               foreach (ushort item in (ushort[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.UInt32:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 4);\r
-                                       else\r
-                                               foreach (uint item in (uint[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.UInt64:\r
-                                       if (array.Length > 2)\r
-                                               BlockWrite (writer, array, 8);\r
-                                       else\r
-                                               foreach (ulong item in (ulong[]) array)\r
-                                                       writer.Write (item);\r
-                                       break;\r
-\r
-                               case TypeCode.String:\r
-                                       foreach (string item in (string[]) array)\r
-                                               writer.Write (item);\r
-                                       break;\r
-\r
-                               default:\r
-                                       if (elementType == typeof (TimeSpan)) {\r
-                                               foreach (TimeSpan item in (TimeSpan[]) array)\r
-                                                       writer.Write (item.Ticks);\r
-                                       }\r
-                                       else\r
-                                               throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);\r
-                                       break;\r
-                       }                       \r
-               }\r
-               \r
-               private void BlockWrite (BinaryWriter writer, Array array, int dataSize)\r
-               {\r
-                       int totalSize = Buffer.ByteLength (array);\r
-                       \r
-                       if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))\r
-                               arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];\r
-                       \r
-                       int pos = 0;\r
-                       while (totalSize > 0) {\r
-                               int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;\r
-                               Buffer.BlockCopy (array, pos, arrayBuffer, 0, size);\r
-                               \r
-                               if (!BitConverter.IsLittleEndian && dataSize > 1)\r
-                                       BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);\r
-                               \r
-                               writer.Write (arrayBuffer, 0, size);\r
-                               totalSize -= size;\r
-                               pos += size;\r
-                       }\r
-               }\r
-\r
-               private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)\r
-               {\r
-                       int numNulls = 0;\r
-                       foreach (object val in array)\r
-                       {\r
-                               if (val != null && numNulls > 0)\r
-                               {\r
-                                       WriteNullFiller (writer, numNulls);\r
-                                       WriteValue (writer, elementType, val);\r
-                                       numNulls = 0;\r
-                               }\r
-                               else if (val == null)\r
-                                       numNulls++;\r
-                               else\r
-                                       WriteValue (writer, elementType, val);\r
-                       }\r
-                       if (numNulls > 0)\r
-                               WriteNullFiller (writer, numNulls);\r
-               }\r
-\r
-               private void WriteNullFiller (BinaryWriter writer, int numNulls)\r
-               {\r
-                       if (numNulls == 1) {\r
-                               writer.Write ((byte) BinaryElement.NullValue);\r
-                       }\r
-                       else if (numNulls == 2) {\r
-                               writer.Write ((byte) BinaryElement.NullValue);\r
-                               writer.Write ((byte) BinaryElement.NullValue);\r
-                       }\r
-                       else if (numNulls <= byte.MaxValue) {\r
-                               writer.Write ((byte) BinaryElement.ArrayFiller8b);\r
-                               writer.Write ((byte) numNulls);\r
-                       }\r
-                       else {\r
-                               writer.Write ((byte) BinaryElement.ArrayFiller32b);\r
-                               writer.Write (numNulls);\r
-                       }\r
-               }\r
-\r
-               private void WriteObjectReference (BinaryWriter writer, long id)\r
-               {\r
-\r
-                       writer.Write ((byte) BinaryElement.ObjectReference);\r
-                       writer.Write ((int)id);\r
-               }\r
-\r
-               public void WriteValue (BinaryWriter writer, Type valueType, object val)\r
-               {\r
-                       if (val == null) \r
-                       {\r
-                               BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);\r
-                               writer.Write ((byte) BinaryElement.NullValue);\r
-                       }\r
-                       else if (BinaryCommon.IsPrimitive(val.GetType()))\r
-                       {\r
-                               if (!BinaryCommon.IsPrimitive(valueType))\r
-                               {\r
-                                       // It is a boxed primitive type value\r
-                                       writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);\r
-                                       WriteTypeSpec (writer, val.GetType());\r
-                               }\r
-                               WritePrimitiveValue (writer, val);\r
-                       }\r
-                       else if (valueType.IsValueType)\r
-                       {\r
-                               // Value types are written embedded in the containing object\r
-                               WriteObjectInstance (writer, val, true);\r
-                       }\r
-                       else if (val is string)\r
-                       {\r
-                               // Strings are written embedded, unless already registered\r
-                               bool firstTime;\r
-                               long id = _idGenerator.GetId (val, out firstTime);\r
-\r
-                               if (firstTime) WriteObjectInstance (writer, val, false);\r
-                               else WriteObjectReference (writer, id);\r
-                       }                       \r
-                       else\r
-                       {\r
-                               // It is a reference type. Write a forward reference and queue the\r
-                               // object to the pending object list (unless already written).\r
-\r
-                               bool firstTime;\r
-                               long id = _idGenerator.GetId (val, out firstTime);\r
-\r
-                               if (firstTime) _pendingObjects.Enqueue (val);\r
-                               WriteObjectReference (writer, id);\r
-                       }\r
-               }\r
-               \r
-               private void WriteString (BinaryWriter writer, long id, string str)\r
-               {\r
-                       writer.Write ((byte) BinaryElement.String);\r
-                       writer.Write ((int)id);\r
-                       writer.Write (str);\r
-               }\r
-\r
-               public int WriteAssembly (BinaryWriter writer, Assembly assembly)\r
-               {\r
-                       return WriteAssemblyName (writer, assembly.FullName);\r
-               }\r
-               \r
-               public int WriteAssemblyName (BinaryWriter writer, string assembly)\r
-               {\r
-                       if (assembly == ObjectWriter.CorlibAssemblyName) return -1;\r
-                       \r
-                       bool firstTime;\r
-                       int id = RegisterAssembly (assembly, out firstTime);\r
-                       if (!firstTime) return id;\r
-                                       \r
-                       writer.Write ((byte) BinaryElement.Assembly);\r
-                       writer.Write (id);\r
-                       if (_assemblyFormat == FormatterAssemblyStyle.Full)\r
-                               writer.Write (assembly);\r
-                       else {\r
-                               int i = assembly.IndexOf (',');\r
-                               if (i != -1) assembly = assembly.Substring (0, i);\r
-                               writer.Write (assembly);\r
-                       }\r
-                               \r
-                       return id;\r
-               }\r
-\r
-               public int GetAssemblyId (Assembly assembly)\r
-               {\r
-                       return GetAssemblyNameId (assembly.FullName);\r
-               }\r
-               \r
-               public int GetAssemblyNameId (string assembly)\r
-               {\r
-                       return (int)_assemblyCache[assembly];\r
-               }\r
-\r
-               private int RegisterAssembly (string assembly, out bool firstTime)\r
-               {\r
-                       if (_assemblyCache.ContainsKey (assembly))\r
-                       {\r
-                               firstTime = false;\r
-                               return (int)_assemblyCache[assembly];\r
-                       }\r
-                       else\r
-                       {\r
-                               int id = (int)_idGenerator.GetId (0, out firstTime);\r
-                               _assemblyCache.Add (assembly, id);\r
-                               return id;\r
-                       }\r
-               }\r
-\r
-               public static void WritePrimitiveValue (BinaryWriter writer, object value)\r
-               {\r
-                       Type type = value.GetType();\r
-\r
-                       switch (Type.GetTypeCode (type))\r
-                       {\r
-                               case TypeCode.Boolean:\r
-                                       writer.Write ((bool)value);\r
-                                       break;\r
-\r
-                               case TypeCode.Byte:\r
-                                       writer.Write ((byte) value);\r
-                                       break;\r
-\r
-                               case TypeCode.Char:\r
-                                       writer.Write ((char) value);\r
-                                       break;\r
-\r
-                               case TypeCode.DateTime: \r
-                                       writer.Write ( ((DateTime)value).Ticks);\r
-                                       break;\r
-\r
-                               case TypeCode.Decimal:\r
-                                       writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));\r
-                                       break;\r
-\r
-                               case TypeCode.Double:\r
-                                       writer.Write ((double) value);\r
-                                       break;\r
-\r
-                               case TypeCode.Int16:\r
-                                       writer.Write ((short) value);\r
-                                       break;\r
-\r
-                               case TypeCode.Int32:\r
-                                       writer.Write ((int) value);\r
-                                       break;\r
-\r
-                               case TypeCode.Int64:\r
-                                       writer.Write ((long) value);\r
-                                       break;\r
-\r
-                               case TypeCode.SByte:\r
-                                       writer.Write ((sbyte) value);\r
-                                       break;\r
-\r
-                               case TypeCode.Single:\r
-                                       writer.Write ((float) value);\r
-                                       break;\r
-\r
-                               case TypeCode.UInt16:\r
-                                       writer.Write ((ushort) value);\r
-                                       break;\r
-\r
-                               case TypeCode.UInt32:\r
-                                       writer.Write ((uint) value);\r
-                                       break;\r
-\r
-                               case TypeCode.UInt64:\r
-                                       writer.Write ((ulong) value);\r
-                                       break;\r
-\r
-                               case TypeCode.String:\r
-                                       writer.Write ((string) value);\r
-                                       break;\r
-\r
-                               default:\r
-                                       if (type == typeof (TimeSpan))\r
-                                               writer.Write (((TimeSpan)value).Ticks);\r
-                                       else\r
-                                               throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);\r
-                                       break;\r
-                       }\r
-               }\r
-\r
-               public static void WriteTypeCode (BinaryWriter writer, Type type)\r
-               {\r
-                       writer.Write ((byte) GetTypeTag (type));\r
-               }\r
-\r
-               public static TypeTag GetTypeTag (Type type)\r
-               {\r
-                       if (type == typeof (string)) {\r
-                               return TypeTag.String;\r
-                       }\r
-                       else if (BinaryCommon.IsPrimitive (type)) {\r
-                               return TypeTag.PrimitiveType;\r
-                       }\r
-                       else if (type == typeof (object)) {\r
-                               return TypeTag.ObjectType;\r
-                       }\r
-                       else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {\r
-                               return TypeTag.ArrayOfObject; \r
-                       }\r
-                       else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){\r
-                               return TypeTag.ArrayOfString;\r
-                       }\r
-                       else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {\r
-                               return TypeTag.ArrayOfPrimitiveType;\r
-                       }\r
-                       else if (type.Assembly == CorlibAssembly) {\r
-                               return TypeTag.RuntimeType;\r
-                       }\r
-                       else\r
-                               return TypeTag.GenericType;\r
-               }\r
-\r
-               public void WriteTypeSpec (BinaryWriter writer, Type type)\r
-               {\r
-                       // WARNING Keep in sync with EmitWriteTypeSpec\r
-                       \r
-                       switch (GetTypeTag (type))\r
-                       {\r
-                               case TypeTag.PrimitiveType:\r
-                                       writer.Write (BinaryCommon.GetTypeCode (type));\r
-                                       break;\r
-\r
-                               case TypeTag.RuntimeType:\r
-                                       writer.Write (type.FullName);\r
-                                       break;\r
-\r
-                               case TypeTag.GenericType:\r
-                                       writer.Write (type.FullName);\r
-                                       writer.Write ((int)GetAssemblyId (type.Assembly));\r
-                                       break;\r
-\r
-                               case TypeTag.ArrayOfPrimitiveType:\r
-                                       writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));\r
-                                       break;\r
-\r
-                               default:\r
-                                       // Type spec not needed\r
-                                       break;\r
-                       }\r
-               }\r
-       }\r
-}\r
+                               default:
+                                       // Type spec not needed
+                                       break;
+                       }
+               }
+       }
+}