4 // Lluis Sanchez Gual (lluis@ideary.com)
6 // (C) 2003 Lluis Sanchez Gual
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Runtime.Serialization;
35 using System.Runtime.Remoting.Messaging;
36 using System.Reflection;
37 using System.Globalization;
39 namespace System.Runtime.Serialization.Formatters.Binary
41 abstract class TypeMetadata
43 public string TypeAssemblyName;
44 public string InstanceTypeName;
46 public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);
47 public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes);
48 public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);
50 public virtual bool IsCompatible (TypeMetadata other)
55 public void BindToName (string assemblyName, string typeName)
57 if (assemblyName != null)
58 TypeAssemblyName = assemblyName;
60 InstanceTypeName = typeName;
63 public abstract bool RequiresTypes { get; }
66 abstract class ClrTypeMetadata: TypeMetadata
68 public Type InstanceType;
70 public ClrTypeMetadata (Type instanceType)
72 InstanceType = instanceType;
73 InstanceTypeName = instanceType.FullName;
74 TypeAssemblyName = instanceType.Assembly.FullName;
77 public override bool RequiresTypes {
82 class SerializableTypeMetadata: TypeMetadata
87 public SerializableTypeMetadata (Type itype, SerializationInfo info)
89 types = new Type [info.MemberCount];
90 names = new string [info.MemberCount];
92 SerializationInfoEnumerator e = info.GetEnumerator ();
97 types[n] = e.ObjectType;
102 TypeAssemblyName = info.AssemblyName;
103 InstanceTypeName = info.FullTypeName;
106 public override bool IsCompatible (TypeMetadata other)
108 if (!(other is SerializableTypeMetadata)) return false;
110 SerializableTypeMetadata tm = (SerializableTypeMetadata)other;
111 if (types.Length != tm.types.Length) return false;
112 if (TypeAssemblyName != tm.TypeAssemblyName) return false;
113 if (InstanceTypeName != tm.InstanceTypeName) return false;
114 for (int n=0; n<types.Length; n++)
116 if (types[n] != tm.types[n]) return false;
117 if (names[n] != tm.names[n]) return false;
122 public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
124 foreach (Type mtype in types)
128 type = type.GetElementType();
130 ow.WriteAssembly (writer, type.Assembly);
134 public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
136 writer.Write (types.Length);
139 foreach (string name in names)
143 foreach (Type type in types)
144 ObjectWriter.WriteTypeCode (writer, type);
146 // Type specs of fields
147 foreach (Type type in types)
148 ow.WriteTypeSpec (writer, type);
151 public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
153 SerializationInfo info = (SerializationInfo) data;
154 SerializationInfoEnumerator e = info.GetEnumerator ();
156 while (e.MoveNext ())
157 ow.WriteValue (writer, e.ObjectType, e.Value);
160 public override bool RequiresTypes {
165 class MemberTypeMetadata: ClrTypeMetadata
167 MemberInfo[] members;
169 public MemberTypeMetadata (Type type, StreamingContext context): base (type)
171 members = FormatterServices.GetSerializableMembers (type, context);
174 public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
176 foreach (FieldInfo field in members)
178 Type type = field.FieldType;
180 type = type.GetElementType();
182 ow.WriteAssembly (writer, type.Assembly);
186 public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
188 writer.Write (members.Length);
191 foreach (FieldInfo field in members)
192 writer.Write (field.Name);
196 foreach (FieldInfo field in members)
197 ObjectWriter.WriteTypeCode (writer, field.FieldType);
199 // Type specs of fields
200 foreach (FieldInfo field in members)
201 ow.WriteTypeSpec (writer, field.FieldType);
205 public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
207 object[] values = FormatterServices.GetObjectData (data, members);
208 for (int n=0; n<values.Length; n++)
209 ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);
213 internal class ObjectWriter
215 ObjectIDGenerator _idGenerator = new ObjectIDGenerator();
216 Hashtable _cachedMetadata = new Hashtable();
217 Queue _pendingObjects = new Queue();
218 Hashtable _assemblyCache = new Hashtable();
220 // Type metadata that can be shared with all serializers
221 static Hashtable _cachedTypes = new Hashtable();
223 internal static Assembly CorlibAssembly = typeof(string).Assembly;
224 internal static string CorlibAssemblyName = typeof(string).Assembly.FullName;
226 ISurrogateSelector _surrogateSelector;
227 StreamingContext _context;
228 FormatterAssemblyStyle _assemblyFormat;
229 FormatterTypeStyle _typeFormat;
230 SerializationBinder _binder;
232 int ArrayBufferLength = 4096;
233 SerializationObjectManager _manager;
235 class MetadataReference
237 public TypeMetadata Metadata;
238 public long ObjectID;
240 public MetadataReference (TypeMetadata metadata, long id)
247 public ObjectWriter (BinaryFormatter formatter)
249 _surrogateSelector = formatter.SurrogateSelector;
250 _context = formatter.Context;
251 _assemblyFormat = formatter.AssemblyFormat;
252 _typeFormat = formatter.TypeFormat;
253 _manager = new SerializationObjectManager (formatter.Context);
254 _binder = formatter.Binder;
257 public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)
259 _pendingObjects.Clear();
260 if (headers != null) QueueObject (headers);
262 WriteQueuedObjects (writer);
263 WriteSerializationEnd (writer);
264 _manager.RaiseOnSerializedEvent ();
267 public void QueueObject (object obj)
269 _pendingObjects.Enqueue (obj);
272 public void WriteQueuedObjects (BinaryWriter writer)
274 while (_pendingObjects.Count > 0)
275 WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);
278 public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)
283 // If the object is a value type (not boxed) then there is no need
284 // to register it in the id generator, because it won't have other
287 if (isValueObject) id = _idGenerator.NextId;
288 else id = _idGenerator.GetId (obj, out firstTime);
291 WriteString (writer, id, (string)obj);
293 else if (obj is Array) {
294 WriteArray (writer, id, (Array)obj);
297 WriteObject (writer, id, obj);
300 public static void WriteSerializationEnd (BinaryWriter writer)
302 writer.Write ((byte) BinaryElement.End);
305 private void WriteObject (BinaryWriter writer, long id, object obj)
308 TypeMetadata metadata;
310 GetObjectData (obj, out metadata, out data);
311 MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceTypeName];
313 if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))
315 // An object of the same type has already been serialized
316 // It is not necessary to write again type metadata
318 writer.Write ((byte) BinaryElement.RefTypeObject);
319 writer.Write ((int)id);
321 writer.Write ((int)metadataReference.ObjectID);
322 metadata.WriteObjectData (this, writer, data);
326 if (metadataReference == null)
328 metadataReference = new MetadataReference (metadata, id);
329 _cachedMetadata [metadata.InstanceTypeName] = metadataReference;
332 bool writeTypes = metadata.RequiresTypes || _typeFormat == FormatterTypeStyle.TypesAlways;
334 BinaryElement objectTag;
337 if (metadata.TypeAssemblyName == CorlibAssemblyName)
340 objectTag = writeTypes ? BinaryElement.RuntimeObject : BinaryElement.UntypedRuntimeObject;
345 objectTag = writeTypes ? BinaryElement.ExternalObject : BinaryElement.UntypedExternalObject;
346 assemblyId = WriteAssemblyName (writer, metadata.TypeAssemblyName);
349 // Registers the assemblies needed for each field
350 // If there are assemblies that where not registered before this object,
353 metadata.WriteAssemblies (this, writer);
357 writer.Write ((byte) objectTag);
358 writer.Write ((int)id);
359 writer.Write (metadata.InstanceTypeName);
361 metadata.WriteTypeData (this, writer, writeTypes);
362 if (assemblyId != -1) writer.Write (assemblyId);
364 metadata.WriteObjectData (this, writer, data);
367 private void GetObjectData (object obj, out TypeMetadata metadata, out object data)
369 Type instanceType = obj.GetType();
370 string binderAssemblyName = null;
371 string binderTypeName = null;
373 _binder.BindToName (instanceType, out binderAssemblyName, out binderTypeName);
374 // Check if the formatter has a surrogate selector, if it does,
375 // check if the surrogate selector handles objects of the given type.
377 if (_surrogateSelector != null)
379 ISurrogateSelector selector;
380 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);
381 if (surrogate != null)
383 SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
384 surrogate.GetObjectData (obj, info, _context);
385 metadata = new SerializableTypeMetadata (instanceType, info);
387 metadata.BindToName (binderAssemblyName, binderTypeName);
394 // Check if the object is marked with the Serializable attribute
396 BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);
398 _manager.RegisterObject (obj);
400 ISerializable ser = obj as ISerializable;
404 SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
405 ser.GetObjectData (info, _context);
406 metadata = new SerializableTypeMetadata (instanceType, info);
408 metadata.BindToName (binderAssemblyName, binderTypeName);
415 if (_context.Context != null)
417 // Don't cache metadata info when the Context property is not null sice
418 // we can't control the number of possible contexts in this case
419 metadata = new MemberTypeMetadata (instanceType, _context);
421 metadata.BindToName (binderAssemblyName, binderTypeName);
426 Hashtable typesTable;
428 lock (_cachedTypes) {
429 typesTable = (Hashtable) _cachedTypes [_context.State];
430 if (typesTable == null) {
431 typesTable = new Hashtable ();
432 _cachedTypes [_context.State] = typesTable;
440 metadata = (TypeMetadata) typesTable [instanceType];
443 if (metadata == null) {
444 metadata = CreateMemberTypeMetadata (instanceType);
446 metadata.BindToName (binderAssemblyName, binderTypeName);
449 typesTable [instanceType] = metadata;
454 TypeMetadata CreateMemberTypeMetadata (Type type)
456 #if !FULL_AOT_RUNTIME
457 if (!BinaryCommon.UseReflectionSerialization) {
458 Type metaType = CodeGenerator.GenerateMetadataType (type, _context);
459 return (TypeMetadata) Activator.CreateInstance (metaType);
463 return new MemberTypeMetadata (type, _context);
466 private void WriteArray (BinaryWriter writer, long id, Array array)
468 // There are 4 ways of serializing arrays:
469 // The element GenericArray (7) can be used for all arrays.
470 // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
471 // arrays of primitive types
472 // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
473 // The element ArrayOfString (17) can be used for single-dimensional string arrays
475 Type elementType = array.GetType().GetElementType();
477 if (elementType == typeof (object) && array.Rank == 1) {
478 WriteObjectArray (writer, id, array);
480 else if (elementType == typeof (string) && array.Rank == 1) {
481 WriteStringArray (writer, id, array);
483 else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {
484 WritePrimitiveTypeArray (writer, id, array);
487 WriteGenericArray (writer, id, array);
490 private void WriteGenericArray (BinaryWriter writer, long id, Array array)
492 Type elementType = array.GetType().GetElementType();
494 // Registers and writes the assembly of the array element type if needed
496 var tag = GetTypeTag (elementType);
497 if ((tag != TypeTag.ArrayOfObject) && (tag != TypeTag.ArrayOfString) && (tag != TypeTag.ArrayOfPrimitiveType))
498 WriteAssembly (writer, elementType.Assembly);
502 writer.Write ((byte) BinaryElement.GenericArray);
503 writer.Write ((int)id);
505 // Write the structure of the array
507 if (elementType.IsArray)
508 writer.Write ((byte) ArrayStructure.Jagged);
509 else if (array.Rank == 1)
510 writer.Write ((byte) ArrayStructure.SingleDimensional);
512 writer.Write ((byte) ArrayStructure.MultiDimensional);
514 // Write the number of dimensions and the length
517 writer.Write (array.Rank);
518 for (int n=0; n<array.Rank; n++)
519 writer.Write (array.GetUpperBound (n) + 1);
522 WriteTypeCode (writer, elementType);
523 WriteTypeSpec (writer, elementType);
525 // Writes the values. For single-dimension array, a special tag is used
526 // to represent multiple consecutive null values. I don't know why this
527 // optimization is not used for multidimensional arrays.
529 if (array.Rank == 1 && !elementType.IsValueType)
531 WriteSingleDimensionArrayElements (writer, array, elementType);
535 foreach (object item in array)
536 WriteValue (writer, elementType, item);
540 private void WriteObjectArray (BinaryWriter writer, long id, Array array)
542 writer.Write ((byte) BinaryElement.ArrayOfObject);
543 writer.Write ((int)id);
544 writer.Write (array.Length); // Single dimension. Just write the length
545 WriteSingleDimensionArrayElements (writer, array, typeof (object));
548 private void WriteStringArray (BinaryWriter writer, long id, Array array)
550 writer.Write ((byte) BinaryElement.ArrayOfString);
551 writer.Write ((int)id);
552 writer.Write (array.Length); // Single dimension. Just write the length
553 WriteSingleDimensionArrayElements (writer, array, typeof (string));
556 private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)
558 writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);
559 writer.Write ((int)id);
560 writer.Write (array.Length); // Single dimension. Just write the length
562 Type elementType = array.GetType().GetElementType();
563 WriteTypeSpec (writer, elementType);
565 switch (Type.GetTypeCode (elementType))
567 case TypeCode.Boolean:
568 foreach (bool item in (bool[]) array)
573 writer.Write ((byte[]) array);
577 writer.Write ((char[]) array);
580 case TypeCode.DateTime:
581 foreach (DateTime item in (DateTime[]) array)
582 writer.Write (item.ToBinary ());
585 case TypeCode.Decimal:
586 foreach (decimal item in (decimal[]) array)
590 case TypeCode.Double:
591 if (array.Length > 2)
592 BlockWrite (writer, array, 8);
594 foreach (double item in (double[]) array)
599 if (array.Length > 2)
600 BlockWrite (writer, array, 2);
602 foreach (short item in (short[]) array)
607 if (array.Length > 2)
608 BlockWrite (writer, array, 4);
610 foreach (int item in (int[]) array)
615 if (array.Length > 2)
616 BlockWrite (writer, array, 8);
618 foreach (long item in (long[]) array)
623 if (array.Length > 2)
624 BlockWrite (writer, array, 1);
626 foreach (sbyte item in (sbyte[]) array)
630 case TypeCode.Single:
631 if (array.Length > 2)
632 BlockWrite (writer, array, 4);
634 foreach (float item in (float[]) array)
638 case TypeCode.UInt16:
639 if (array.Length > 2)
640 BlockWrite (writer, array, 2);
642 foreach (ushort item in (ushort[]) array)
646 case TypeCode.UInt32:
647 if (array.Length > 2)
648 BlockWrite (writer, array, 4);
650 foreach (uint item in (uint[]) array)
654 case TypeCode.UInt64:
655 if (array.Length > 2)
656 BlockWrite (writer, array, 8);
658 foreach (ulong item in (ulong[]) array)
662 case TypeCode.String:
663 foreach (string item in (string[]) array)
668 if (elementType == typeof (TimeSpan)) {
669 foreach (TimeSpan item in (TimeSpan[]) array)
670 writer.Write (item.Ticks);
673 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
678 private void BlockWrite (BinaryWriter writer, Array array, int dataSize)
680 int totalSize = Buffer.ByteLength (array);
682 if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
683 arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
686 while (totalSize > 0) {
687 int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
688 Buffer.BlockCopy (array, pos, arrayBuffer, 0, size);
690 if (!BitConverter.IsLittleEndian && dataSize > 1)
691 BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
693 writer.Write (arrayBuffer, 0, size);
699 private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)
702 foreach (object val in array)
704 if (val != null && numNulls > 0)
706 WriteNullFiller (writer, numNulls);
707 WriteValue (writer, elementType, val);
710 else if (val == null)
713 WriteValue (writer, elementType, val);
716 WriteNullFiller (writer, numNulls);
719 private void WriteNullFiller (BinaryWriter writer, int numNulls)
722 writer.Write ((byte) BinaryElement.NullValue);
724 else if (numNulls == 2) {
725 writer.Write ((byte) BinaryElement.NullValue);
726 writer.Write ((byte) BinaryElement.NullValue);
728 else if (numNulls <= byte.MaxValue) {
729 writer.Write ((byte) BinaryElement.ArrayFiller8b);
730 writer.Write ((byte) numNulls);
733 writer.Write ((byte) BinaryElement.ArrayFiller32b);
734 writer.Write (numNulls);
738 private void WriteObjectReference (BinaryWriter writer, long id)
741 writer.Write ((byte) BinaryElement.ObjectReference);
742 writer.Write ((int)id);
745 public void WriteValue (BinaryWriter writer, Type valueType, object val)
749 BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);
750 writer.Write ((byte) BinaryElement.NullValue);
752 else if (BinaryCommon.IsPrimitive(val.GetType()))
754 if (!BinaryCommon.IsPrimitive(valueType))
756 // It is a boxed primitive type value
757 writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);
758 WriteTypeSpec (writer, val.GetType());
760 WritePrimitiveValue (writer, val);
762 else if (valueType.IsValueType)
764 // Value types are written embedded in the containing object
765 WriteObjectInstance (writer, val, true);
767 else if (val is string)
769 // Strings are written embedded, unless already registered
771 long id = _idGenerator.GetId (val, out firstTime);
773 if (firstTime) WriteObjectInstance (writer, val, false);
774 else WriteObjectReference (writer, id);
778 // It is a reference type. Write a forward reference and queue the
779 // object to the pending object list (unless already written).
782 long id = _idGenerator.GetId (val, out firstTime);
784 if (firstTime) _pendingObjects.Enqueue (val);
785 WriteObjectReference (writer, id);
789 private void WriteString (BinaryWriter writer, long id, string str)
791 writer.Write ((byte) BinaryElement.String);
792 writer.Write ((int)id);
796 public int WriteAssembly (BinaryWriter writer, Assembly assembly)
798 return WriteAssemblyName (writer, assembly.FullName);
801 public int WriteAssemblyName (BinaryWriter writer, string assembly)
803 if (assembly == ObjectWriter.CorlibAssemblyName) return -1;
806 int id = RegisterAssembly (assembly, out firstTime);
807 if (!firstTime) return id;
809 writer.Write ((byte) BinaryElement.Assembly);
811 if (_assemblyFormat == FormatterAssemblyStyle.Full)
812 writer.Write (assembly);
814 int i = assembly.IndexOf (',');
815 if (i != -1) assembly = assembly.Substring (0, i);
816 writer.Write (assembly);
822 public int GetAssemblyId (Assembly assembly)
824 return GetAssemblyNameId (assembly.FullName);
827 public int GetAssemblyNameId (string assembly)
829 return (int)_assemblyCache[assembly];
832 private int RegisterAssembly (string assembly, out bool firstTime)
834 if (_assemblyCache.ContainsKey (assembly))
837 return (int)_assemblyCache[assembly];
841 int id = (int)_idGenerator.GetId (0, out firstTime);
842 _assemblyCache.Add (assembly, id);
847 public static void WritePrimitiveValue (BinaryWriter writer, object value)
849 Type type = value.GetType();
851 switch (Type.GetTypeCode (type))
853 case TypeCode.Boolean:
854 writer.Write ((bool)value);
858 writer.Write ((byte) value);
862 writer.Write ((char) value);
865 case TypeCode.DateTime:
866 writer.Write ( ((DateTime)value).ToBinary ());
869 case TypeCode.Decimal:
870 writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));
873 case TypeCode.Double:
874 writer.Write ((double) value);
878 writer.Write ((short) value);
882 writer.Write ((int) value);
886 writer.Write ((long) value);
890 writer.Write ((sbyte) value);
893 case TypeCode.Single:
894 writer.Write ((float) value);
897 case TypeCode.UInt16:
898 writer.Write ((ushort) value);
901 case TypeCode.UInt32:
902 writer.Write ((uint) value);
905 case TypeCode.UInt64:
906 writer.Write ((ulong) value);
909 case TypeCode.String:
910 writer.Write ((string) value);
914 if (type == typeof (TimeSpan))
915 writer.Write (((TimeSpan)value).Ticks);
917 throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);
922 public static void WriteTypeCode (BinaryWriter writer, Type type)
924 writer.Write ((byte) GetTypeTag (type));
927 public static TypeTag GetTypeTag (Type type)
929 if (type == typeof (string)) {
930 return TypeTag.String;
932 else if (BinaryCommon.IsPrimitive (type)) {
933 return TypeTag.PrimitiveType;
935 else if (type == typeof (object)) {
936 return TypeTag.ObjectType;
938 else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {
939 return TypeTag.ArrayOfObject;
941 else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){
942 return TypeTag.ArrayOfString;
944 else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {
945 return TypeTag.ArrayOfPrimitiveType;
947 else if (type.Assembly == CorlibAssembly) {
948 return TypeTag.RuntimeType;
951 return TypeTag.GenericType;
954 public void WriteTypeSpec (BinaryWriter writer, Type type)
956 // WARNING Keep in sync with EmitWriteTypeSpec
958 switch (GetTypeTag (type))
960 case TypeTag.PrimitiveType:
961 writer.Write (BinaryCommon.GetTypeCode (type));
964 case TypeTag.RuntimeType:
965 string fullName = type.FullName;
966 // Map System.MonoType to MS.NET's System.RuntimeType,
967 // when called in remoting context.
968 // Note that this code does not need to be in sync with
969 // EmitWriteTypeSpec because serializing a MethodCall
970 // won't trigger the CodeGenerator.
971 if (_context.State == StreamingContextStates.Remoting)
972 if (type == typeof (System.MonoType))
973 fullName = "System.RuntimeType";
974 else if (type == typeof (System.MonoType[]))
975 fullName = "System.RuntimeType[]";
976 writer.Write (fullName);
979 case TypeTag.GenericType:
980 writer.Write (type.FullName);
981 writer.Write ((int)GetAssemblyId (type.Assembly));
984 case TypeTag.ArrayOfPrimitiveType:
985 writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));
989 // Type spec not needed