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 abstract bool RequiresTypes { get; }
58 abstract class ClrTypeMetadata
: TypeMetadata
60 public Type InstanceType
;
62 public ClrTypeMetadata (Type instanceType
)
64 InstanceType
= instanceType
;
65 InstanceTypeName
= instanceType
.FullName
;
66 TypeAssemblyName
= instanceType
.Assembly
.FullName
;
69 public override bool RequiresTypes
{
74 class SerializableTypeMetadata
: TypeMetadata
79 public SerializableTypeMetadata (Type itype
, SerializationInfo info
)
81 types
= new Type
[info
.MemberCount
];
82 names
= new string [info
.MemberCount
];
84 SerializationInfoEnumerator e
= info
.GetEnumerator ();
89 types
[n
] = e
.ObjectType
;
94 TypeAssemblyName
= info
.AssemblyName
;
95 InstanceTypeName
= info
.FullTypeName
;
98 public override bool IsCompatible (TypeMetadata other
)
100 if (!(other
is SerializableTypeMetadata
)) return false;
102 SerializableTypeMetadata tm
= (SerializableTypeMetadata
)other
;
103 if (types
.Length
!= tm
.types
.Length
) return false;
104 if (TypeAssemblyName
!= tm
.TypeAssemblyName
) return false;
105 if (InstanceTypeName
!= tm
.InstanceTypeName
) return false;
106 for (int n
=0; n
<types
.Length
; n
++)
108 if (types
[n
] != tm
.types
[n
]) return false;
109 if (names
[n
] != tm
.names
[n
]) return false;
114 public override void WriteAssemblies (ObjectWriter ow
, BinaryWriter writer
)
116 foreach (Type mtype
in types
)
120 type
= type
.GetElementType();
122 ow
.WriteAssembly (writer
, type
.Assembly
);
126 public override void WriteTypeData (ObjectWriter ow
, BinaryWriter writer
, bool writeTypes
)
128 writer
.Write (types
.Length
);
131 foreach (string name
in names
)
135 foreach (Type type
in types
)
136 ObjectWriter
.WriteTypeCode (writer
, type
);
138 // Type specs of fields
139 foreach (Type type
in types
)
140 ow
.WriteTypeSpec (writer
, type
);
143 public override void WriteObjectData (ObjectWriter ow
, BinaryWriter writer
, object data
)
145 SerializationInfo info
= (SerializationInfo
) data
;
146 SerializationInfoEnumerator e
= info
.GetEnumerator ();
148 while (e
.MoveNext ())
149 ow
.WriteValue (writer
, e
.ObjectType
, e
.Value
);
152 public override bool RequiresTypes
{
157 class MemberTypeMetadata
: ClrTypeMetadata
159 MemberInfo
[] members
;
161 public MemberTypeMetadata (Type type
, StreamingContext context
): base (type
)
163 members
= FormatterServices
.GetSerializableMembers (type
, context
);
166 public override void WriteAssemblies (ObjectWriter ow
, BinaryWriter writer
)
168 foreach (FieldInfo field
in members
)
170 Type type
= field
.FieldType
;
172 type
= type
.GetElementType();
174 ow
.WriteAssembly (writer
, type
.Assembly
);
178 public override void WriteTypeData (ObjectWriter ow
, BinaryWriter writer
, bool writeTypes
)
180 writer
.Write (members
.Length
);
183 foreach (FieldInfo field
in members
)
184 writer
.Write (field
.Name
);
188 foreach (FieldInfo field
in members
)
189 ObjectWriter
.WriteTypeCode (writer
, field
.FieldType
);
191 // Type specs of fields
192 foreach (FieldInfo field
in members
)
193 ow
.WriteTypeSpec (writer
, field
.FieldType
);
197 public override void WriteObjectData (ObjectWriter ow
, BinaryWriter writer
, object data
)
199 object[] values
= FormatterServices
.GetObjectData (data
, members
);
200 for (int n
=0; n
<values
.Length
; n
++)
201 ow
.WriteValue (writer
, ((FieldInfo
)members
[n
]).FieldType
, values
[n
]);
205 internal class ObjectWriter
207 ObjectIDGenerator _idGenerator
= new ObjectIDGenerator();
208 Hashtable _cachedMetadata
= new Hashtable();
209 Queue _pendingObjects
= new Queue();
210 Hashtable _assemblyCache
= new Hashtable();
212 // Type metadata that can be shared with all serializers
213 static Hashtable _cachedTypes
= new Hashtable();
215 internal static Assembly CorlibAssembly
= typeof(string).Assembly
;
216 internal static string CorlibAssemblyName
= typeof(string).Assembly
.FullName
;
218 ISurrogateSelector _surrogateSelector
;
219 StreamingContext _context
;
220 FormatterAssemblyStyle _assemblyFormat
;
221 FormatterTypeStyle _typeFormat
;
223 int ArrayBufferLength
= 4096;
225 SerializationObjectManager _manager
;
228 class MetadataReference
230 public TypeMetadata Metadata
;
231 public long ObjectID
;
233 public MetadataReference (TypeMetadata metadata
, long id
)
240 public ObjectWriter (ISurrogateSelector surrogateSelector
, StreamingContext context
, FormatterAssemblyStyle assemblyFormat
, FormatterTypeStyle typeFormat
)
242 _surrogateSelector
= surrogateSelector
;
244 _assemblyFormat
= assemblyFormat
;
245 _typeFormat
= typeFormat
;
247 _manager
= new SerializationObjectManager (context
);
251 public void WriteObjectGraph (BinaryWriter writer
, object obj
, Header
[] headers
)
253 _pendingObjects
.Clear();
254 if (headers
!= null) QueueObject (headers
);
256 WriteQueuedObjects (writer
);
257 WriteSerializationEnd (writer
);
259 _manager
.RaiseOnSerializedEvent ();
263 public void QueueObject (object obj
)
265 _pendingObjects
.Enqueue (obj
);
268 public void WriteQueuedObjects (BinaryWriter writer
)
270 while (_pendingObjects
.Count
> 0)
271 WriteObjectInstance (writer
, _pendingObjects
.Dequeue(), false);
274 public void WriteObjectInstance (BinaryWriter writer
, object obj
, bool isValueObject
)
279 // If the object is a value type (not boxed) then there is no need
280 // to register it in the id generator, because it won't have other
283 if (isValueObject
) id
= _idGenerator
.NextId
;
284 else id
= _idGenerator
.GetId (obj
, out firstTime
);
287 WriteString (writer
, id
, (string)obj
);
289 else if (obj
is Array
) {
290 WriteArray (writer
, id
, (Array
)obj
);
293 WriteObject (writer
, id
, obj
);
296 public static void WriteSerializationEnd (BinaryWriter writer
)
298 writer
.Write ((byte) BinaryElement
.End
);
301 private void WriteObject (BinaryWriter writer
, long id
, object obj
)
304 TypeMetadata metadata
;
306 GetObjectData (obj
, out metadata
, out data
);
307 MetadataReference metadataReference
= (MetadataReference
)_cachedMetadata
[metadata
.InstanceTypeName
];
309 if (metadataReference
!= null && metadata
.IsCompatible (metadataReference
.Metadata
))
311 // An object of the same type has already been serialized
312 // It is not necessary to write again type metadata
314 writer
.Write ((byte) BinaryElement
.RefTypeObject
);
315 writer
.Write ((int)id
);
317 writer
.Write ((int)metadataReference
.ObjectID
);
318 metadata
.WriteObjectData (this, writer
, data
);
322 if (metadataReference
== null)
324 metadataReference
= new MetadataReference (metadata
, id
);
325 _cachedMetadata
[metadata
.InstanceTypeName
] = metadataReference
;
328 bool writeTypes
= metadata
.RequiresTypes
|| _typeFormat
== FormatterTypeStyle
.TypesAlways
;
330 BinaryElement objectTag
;
333 if (metadata
.TypeAssemblyName
== CorlibAssemblyName
)
336 objectTag
= writeTypes
? BinaryElement
.RuntimeObject
: BinaryElement
.UntypedRuntimeObject
;
341 objectTag
= writeTypes
? BinaryElement
.ExternalObject
: BinaryElement
.UntypedExternalObject
;
342 assemblyId
= WriteAssemblyName (writer
, metadata
.TypeAssemblyName
);
345 // Registers the assemblies needed for each field
346 // If there are assemblies that where not registered before this object,
349 metadata
.WriteAssemblies (this, writer
);
353 writer
.Write ((byte) objectTag
);
354 writer
.Write ((int)id
);
355 writer
.Write (metadata
.InstanceTypeName
);
357 metadata
.WriteTypeData (this, writer
, writeTypes
);
358 if (assemblyId
!= -1) writer
.Write (assemblyId
);
360 metadata
.WriteObjectData (this, writer
, data
);
363 private void GetObjectData (object obj
, out TypeMetadata metadata
, out object data
)
365 Type instanceType
= obj
.GetType();
367 // Check if the formatter has a surrogate selector, if it does,
368 // check if the surrogate selector handles objects of the given type.
370 if (_surrogateSelector
!= null)
372 ISurrogateSelector selector
;
373 ISerializationSurrogate surrogate
= _surrogateSelector
.GetSurrogate (instanceType
, _context
, out selector
);
374 if (surrogate
!= null)
376 SerializationInfo info
= new SerializationInfo (instanceType
, new FormatterConverter ());
377 surrogate
.GetObjectData (obj
, info
, _context
);
378 metadata
= new SerializableTypeMetadata (instanceType
, info
);
384 // Check if the object is marked with the Serializable attribute
386 BinaryCommon
.CheckSerializable (instanceType
, _surrogateSelector
, _context
);
389 _manager
.RegisterObject (obj
);
392 ISerializable ser
= obj
as ISerializable
;
396 SerializationInfo info
= new SerializationInfo (instanceType
, new FormatterConverter ());
397 ser
.GetObjectData (info
, _context
);
398 metadata
= new SerializableTypeMetadata (instanceType
, info
);
404 if (_context
.Context
!= null)
406 // Don't cache metadata info when the Context property is not null sice
407 // we can't control the number of possible contexts in this case
408 metadata
= new MemberTypeMetadata (instanceType
, _context
);
412 Hashtable typesTable
;
414 lock (_cachedTypes
) {
415 typesTable
= (Hashtable
) _cachedTypes
[_context
.State
];
416 if (typesTable
== null) {
417 typesTable
= new Hashtable ();
418 _cachedTypes
[_context
.State
] = typesTable
;
426 metadata
= (TypeMetadata
) typesTable
[instanceType
];
429 if (metadata
== null) {
430 metadata
= CreateMemberTypeMetadata (instanceType
);
433 typesTable
[instanceType
] = metadata
;
438 TypeMetadata
CreateMemberTypeMetadata (Type type
)
440 if (!BinaryCommon
.UseReflectionSerialization
) {
441 Type metaType
= CodeGenerator
.GenerateMetadataType (type
, _context
);
442 return (TypeMetadata
) Activator
.CreateInstance (metaType
);
445 return new MemberTypeMetadata (type
, _context
);
448 private void WriteArray (BinaryWriter writer
, long id
, Array array
)
450 // There are 4 ways of serializing arrays:
451 // The element GenericArray (7) can be used for all arrays.
452 // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
453 // arrays of primitive types
454 // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
455 // The element ArrayOfString (17) can be used for single-dimensional string arrays
457 Type elementType
= array
.GetType().GetElementType();
459 if (elementType
== typeof (object) && array
.Rank
== 1) {
460 WriteObjectArray (writer
, id
, array
);
462 else if (elementType
== typeof (string) && array
.Rank
== 1) {
463 WriteStringArray (writer
, id
, array
);
465 else if (BinaryCommon
.IsPrimitive(elementType
) && array
.Rank
== 1) {
466 WritePrimitiveTypeArray (writer
, id
, array
);
469 WriteGenericArray (writer
, id
, array
);
472 private void WriteGenericArray (BinaryWriter writer
, long id
, Array array
)
474 Type elementType
= array
.GetType().GetElementType();
476 // Registers and writes the assembly of the array element type if needed
478 if (!elementType
.IsArray
)
479 WriteAssembly (writer
, elementType
.Assembly
);
483 writer
.Write ((byte) BinaryElement
.GenericArray
);
484 writer
.Write ((int)id
);
486 // Write the structure of the array
488 if (elementType
.IsArray
)
489 writer
.Write ((byte) ArrayStructure
.Jagged
);
490 else if (array
.Rank
== 1)
491 writer
.Write ((byte) ArrayStructure
.SingleDimensional
);
493 writer
.Write ((byte) ArrayStructure
.MultiDimensional
);
495 // Write the number of dimensions and the length
498 writer
.Write (array
.Rank
);
499 for (int n
=0; n
<array
.Rank
; n
++)
500 writer
.Write (array
.GetUpperBound (n
) + 1);
503 WriteTypeCode (writer
, elementType
);
504 WriteTypeSpec (writer
, elementType
);
506 // Writes the values. For single-dimension array, a special tag is used
507 // to represent multiple consecutive null values. I don't know why this
508 // optimization is not used for multidimensional arrays.
510 if (array
.Rank
== 1 && !elementType
.IsValueType
)
512 WriteSingleDimensionArrayElements (writer
, array
, elementType
);
516 foreach (object item
in array
)
517 WriteValue (writer
, elementType
, item
);
521 private void WriteObjectArray (BinaryWriter writer
, long id
, Array array
)
523 writer
.Write ((byte) BinaryElement
.ArrayOfObject
);
524 writer
.Write ((int)id
);
525 writer
.Write (array
.Length
); // Single dimension. Just write the length
526 WriteSingleDimensionArrayElements (writer
, array
, typeof (object));
529 private void WriteStringArray (BinaryWriter writer
, long id
, Array array
)
531 writer
.Write ((byte) BinaryElement
.ArrayOfString
);
532 writer
.Write ((int)id
);
533 writer
.Write (array
.Length
); // Single dimension. Just write the length
534 WriteSingleDimensionArrayElements (writer
, array
, typeof (string));
537 private void WritePrimitiveTypeArray (BinaryWriter writer
, long id
, Array array
)
539 writer
.Write ((byte) BinaryElement
.ArrayOfPrimitiveType
);
540 writer
.Write ((int)id
);
541 writer
.Write (array
.Length
); // Single dimension. Just write the length
543 Type elementType
= array
.GetType().GetElementType();
544 WriteTypeSpec (writer
, elementType
);
546 switch (Type
.GetTypeCode (elementType
))
548 case TypeCode
.Boolean
:
549 foreach (bool item
in (bool[]) array
)
554 writer
.Write ((byte[]) array
);
558 writer
.Write ((char[]) array
);
561 case TypeCode
.DateTime
:
562 foreach (DateTime item
in (DateTime
[]) array
) {
563 ulong val
= (ulong) item
.Ticks
;
565 val
|= ((ulong) item
.Kind
) << 62;
571 case TypeCode
.Decimal
:
572 foreach (decimal item
in (decimal[]) array
)
576 case TypeCode
.Double
:
577 if (array
.Length
> 2)
578 BlockWrite (writer
, array
, 8);
580 foreach (double item
in (double[]) array
)
585 if (array
.Length
> 2)
586 BlockWrite (writer
, array
, 2);
588 foreach (short item
in (short[]) array
)
593 if (array
.Length
> 2)
594 BlockWrite (writer
, array
, 4);
596 foreach (int item
in (int[]) array
)
601 if (array
.Length
> 2)
602 BlockWrite (writer
, array
, 8);
604 foreach (long item
in (long[]) array
)
609 if (array
.Length
> 2)
610 BlockWrite (writer
, array
, 1);
612 foreach (sbyte item
in (sbyte[]) array
)
616 case TypeCode
.Single
:
617 if (array
.Length
> 2)
618 BlockWrite (writer
, array
, 4);
620 foreach (float item
in (float[]) array
)
624 case TypeCode
.UInt16
:
625 if (array
.Length
> 2)
626 BlockWrite (writer
, array
, 2);
628 foreach (ushort item
in (ushort[]) array
)
632 case TypeCode
.UInt32
:
633 if (array
.Length
> 2)
634 BlockWrite (writer
, array
, 4);
636 foreach (uint item
in (uint[]) array
)
640 case TypeCode
.UInt64
:
641 if (array
.Length
> 2)
642 BlockWrite (writer
, array
, 8);
644 foreach (ulong item
in (ulong[]) array
)
648 case TypeCode
.String
:
649 foreach (string item
in (string[]) array
)
654 if (elementType
== typeof (TimeSpan
)) {
655 foreach (TimeSpan item
in (TimeSpan
[]) array
)
656 writer
.Write (item
.Ticks
);
659 throw new NotSupportedException ("Unsupported primitive type: " + elementType
.FullName
);
664 private void BlockWrite (BinaryWriter writer
, Array array
, int dataSize
)
666 int totalSize
= Buffer
.ByteLength (array
);
668 if (arrayBuffer
== null || (totalSize
> arrayBuffer
.Length
&& arrayBuffer
.Length
!= ArrayBufferLength
))
669 arrayBuffer
= new byte [totalSize
<= ArrayBufferLength
? totalSize
: ArrayBufferLength
];
672 while (totalSize
> 0) {
673 int size
= totalSize
< arrayBuffer
.Length
? totalSize
: arrayBuffer
.Length
;
674 Buffer
.BlockCopy (array
, pos
, arrayBuffer
, 0, size
);
676 if (!BitConverter
.IsLittleEndian
&& dataSize
> 1)
677 BinaryCommon
.SwapBytes (arrayBuffer
, size
, dataSize
);
679 writer
.Write (arrayBuffer
, 0, size
);
685 private void WriteSingleDimensionArrayElements (BinaryWriter writer
, Array array
, Type elementType
)
688 foreach (object val
in array
)
690 if (val
!= null && numNulls
> 0)
692 WriteNullFiller (writer
, numNulls
);
693 WriteValue (writer
, elementType
, val
);
696 else if (val
== null)
699 WriteValue (writer
, elementType
, val
);
702 WriteNullFiller (writer
, numNulls
);
705 private void WriteNullFiller (BinaryWriter writer
, int numNulls
)
708 writer
.Write ((byte) BinaryElement
.NullValue
);
710 else if (numNulls
== 2) {
711 writer
.Write ((byte) BinaryElement
.NullValue
);
712 writer
.Write ((byte) BinaryElement
.NullValue
);
714 else if (numNulls
<= byte.MaxValue
) {
715 writer
.Write ((byte) BinaryElement
.ArrayFiller8b
);
716 writer
.Write ((byte) numNulls
);
719 writer
.Write ((byte) BinaryElement
.ArrayFiller32b
);
720 writer
.Write (numNulls
);
724 private void WriteObjectReference (BinaryWriter writer
, long id
)
727 writer
.Write ((byte) BinaryElement
.ObjectReference
);
728 writer
.Write ((int)id
);
731 public void WriteValue (BinaryWriter writer
, Type valueType
, object val
)
735 BinaryCommon
.CheckSerializable (valueType
, _surrogateSelector
, _context
);
736 writer
.Write ((byte) BinaryElement
.NullValue
);
738 else if (BinaryCommon
.IsPrimitive(val
.GetType()))
740 if (!BinaryCommon
.IsPrimitive(valueType
))
742 // It is a boxed primitive type value
743 writer
.Write ((byte) BinaryElement
.BoxedPrimitiveTypeValue
);
744 WriteTypeSpec (writer
, val
.GetType());
746 WritePrimitiveValue (writer
, val
);
748 else if (valueType
.IsValueType
)
750 // Value types are written embedded in the containing object
751 WriteObjectInstance (writer
, val
, true);
753 else if (val
is string)
755 // Strings are written embedded, unless already registered
757 long id
= _idGenerator
.GetId (val
, out firstTime
);
759 if (firstTime
) WriteObjectInstance (writer
, val
, false);
760 else WriteObjectReference (writer
, id
);
764 // It is a reference type. Write a forward reference and queue the
765 // object to the pending object list (unless already written).
768 long id
= _idGenerator
.GetId (val
, out firstTime
);
770 if (firstTime
) _pendingObjects
.Enqueue (val
);
771 WriteObjectReference (writer
, id
);
775 private void WriteString (BinaryWriter writer
, long id
, string str
)
777 writer
.Write ((byte) BinaryElement
.String
);
778 writer
.Write ((int)id
);
782 public int WriteAssembly (BinaryWriter writer
, Assembly assembly
)
784 return WriteAssemblyName (writer
, assembly
.FullName
);
787 public int WriteAssemblyName (BinaryWriter writer
, string assembly
)
789 if (assembly
== ObjectWriter
.CorlibAssemblyName
) return -1;
792 int id
= RegisterAssembly (assembly
, out firstTime
);
793 if (!firstTime
) return id
;
795 writer
.Write ((byte) BinaryElement
.Assembly
);
797 if (_assemblyFormat
== FormatterAssemblyStyle
.Full
)
798 writer
.Write (assembly
);
800 int i
= assembly
.IndexOf (',');
801 if (i
!= -1) assembly
= assembly
.Substring (0, i
);
802 writer
.Write (assembly
);
808 public int GetAssemblyId (Assembly assembly
)
810 return GetAssemblyNameId (assembly
.FullName
);
813 public int GetAssemblyNameId (string assembly
)
815 return (int)_assemblyCache
[assembly
];
818 private int RegisterAssembly (string assembly
, out bool firstTime
)
820 if (_assemblyCache
.ContainsKey (assembly
))
823 return (int)_assemblyCache
[assembly
];
827 int id
= (int)_idGenerator
.GetId (0, out firstTime
);
828 _assemblyCache
.Add (assembly
, id
);
833 public static void WritePrimitiveValue (BinaryWriter writer
, object value)
835 Type type
= value.GetType();
837 switch (Type
.GetTypeCode (type
))
839 case TypeCode
.Boolean
:
840 writer
.Write ((bool)value);
844 writer
.Write ((byte) value);
848 writer
.Write ((char) value);
851 case TypeCode
.DateTime
:
852 writer
.Write ( ((DateTime
)value).Ticks
);
855 case TypeCode
.Decimal
:
856 writer
.Write (((decimal) value).ToString (CultureInfo
.InvariantCulture
));
859 case TypeCode
.Double
:
860 writer
.Write ((double) value);
864 writer
.Write ((short) value);
868 writer
.Write ((int) value);
872 writer
.Write ((long) value);
876 writer
.Write ((sbyte) value);
879 case TypeCode
.Single
:
880 writer
.Write ((float) value);
883 case TypeCode
.UInt16
:
884 writer
.Write ((ushort) value);
887 case TypeCode
.UInt32
:
888 writer
.Write ((uint) value);
891 case TypeCode
.UInt64
:
892 writer
.Write ((ulong) value);
895 case TypeCode
.String
:
896 writer
.Write ((string) value);
900 if (type
== typeof (TimeSpan
))
901 writer
.Write (((TimeSpan
)value).Ticks
);
903 throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName
);
908 public static void WriteTypeCode (BinaryWriter writer
, Type type
)
910 writer
.Write ((byte) GetTypeTag (type
));
913 public static TypeTag
GetTypeTag (Type type
)
915 if (type
== typeof (string)) {
916 return TypeTag
.String
;
918 else if (BinaryCommon
.IsPrimitive (type
)) {
919 return TypeTag
.PrimitiveType
;
921 else if (type
== typeof (object)) {
922 return TypeTag
.ObjectType
;
924 else if (type
.IsArray
&& type
.GetArrayRank() == 1 && type
.GetElementType() == typeof (object)) {
925 return TypeTag
.ArrayOfObject
;
927 else if (type
.IsArray
&& type
.GetArrayRank() == 1 && type
.GetElementType() == typeof (string)){
928 return TypeTag
.ArrayOfString
;
930 else if (type
.IsArray
&& type
.GetArrayRank() == 1 && BinaryCommon
.IsPrimitive(type
.GetElementType())) {
931 return TypeTag
.ArrayOfPrimitiveType
;
933 else if (type
.Assembly
== CorlibAssembly
) {
934 return TypeTag
.RuntimeType
;
937 return TypeTag
.GenericType
;
940 public void WriteTypeSpec (BinaryWriter writer
, Type type
)
942 // WARNING Keep in sync with EmitWriteTypeSpec
944 switch (GetTypeTag (type
))
946 case TypeTag
.PrimitiveType
:
947 writer
.Write (BinaryCommon
.GetTypeCode (type
));
950 case TypeTag
.RuntimeType
:
951 string fullName
= type
.FullName
;
953 // Map System.MonoType to MS.NET's System.RuntimeType,
954 // when called in remoting context.
955 // Note that this code does not need to be in sync with
956 // EmitWriteTypeSpec because serializing a MethodCall
957 // won't trigger the CodeGenerator.
958 if (_context
.State
== StreamingContextStates
.Remoting
)
959 if (type
== typeof (System
.MonoType
))
960 fullName
= "System.RuntimeType";
962 writer
.Write (fullName
);
965 case TypeTag
.GenericType
:
966 writer
.Write (type
.FullName
);
967 writer
.Write ((int)GetAssemblyId (type
.Assembly
));
970 case TypeTag
.ArrayOfPrimitiveType
:
971 writer
.Write (BinaryCommon
.GetTypeCode (type
.GetElementType()));
975 // Type spec not needed