4 // Lluis Sanchez Gual (lluis@ideary.com)
\r
6 // (C) 2003 Lluis Sanchez Gual
\r
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;
\r
34 using System.Runtime.Serialization;
\r
35 using System.Runtime.Remoting.Messaging;
\r
36 using System.Reflection;
\r
37 using System.Globalization;
\r
39 namespace System.Runtime.Serialization.Formatters.Binary
\r
41 abstract class TypeMetadata
\r
43 public string TypeAssemblyName;
\r
44 public string InstanceTypeName;
\r
46 public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);
\r
47 public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes);
\r
48 public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);
\r
50 public virtual bool IsCompatible (TypeMetadata other)
\r
55 public abstract bool RequiresTypes { get; }
\r
58 abstract class ClrTypeMetadata: TypeMetadata
\r
60 public Type InstanceType;
\r
62 public ClrTypeMetadata (Type instanceType)
\r
64 InstanceType = instanceType;
\r
65 InstanceTypeName = instanceType.FullName;
\r
66 TypeAssemblyName = instanceType.Assembly.FullName;
\r
69 public override bool RequiresTypes {
\r
70 get { return false; }
\r
74 class SerializableTypeMetadata: TypeMetadata
\r
79 public SerializableTypeMetadata (Type itype, SerializationInfo info)
\r
81 types = new Type [info.MemberCount];
\r
82 names = new string [info.MemberCount];
\r
84 SerializationInfoEnumerator e = info.GetEnumerator ();
\r
87 while (e.MoveNext ())
\r
89 types[n] = e.ObjectType;
\r
94 TypeAssemblyName = info.AssemblyName;
\r
95 InstanceTypeName = info.FullTypeName;
\r
98 public override bool IsCompatible (TypeMetadata other)
\r
100 if (!(other is SerializableTypeMetadata)) return false;
\r
102 SerializableTypeMetadata tm = (SerializableTypeMetadata)other;
\r
103 if (types.Length != tm.types.Length) return false;
\r
104 if (TypeAssemblyName != tm.TypeAssemblyName) return false;
\r
105 if (InstanceTypeName != tm.InstanceTypeName) return false;
\r
106 for (int n=0; n<types.Length; n++)
\r
108 if (types[n] != tm.types[n]) return false;
\r
109 if (names[n] != tm.names[n]) return false;
\r
114 public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
\r
116 foreach (Type mtype in types)
\r
119 while (type.IsArray)
\r
120 type = type.GetElementType();
\r
122 ow.WriteAssembly (writer, type.Assembly);
\r
126 public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
\r
128 writer.Write (types.Length);
\r
131 foreach (string name in names)
\r
132 writer.Write (name);
\r
135 foreach (Type type in types)
\r
136 ObjectWriter.WriteTypeCode (writer, type);
\r
138 // Type specs of fields
\r
139 foreach (Type type in types)
\r
140 ow.WriteTypeSpec (writer, type);
\r
143 public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
\r
145 SerializationInfo info = (SerializationInfo) data;
\r
146 SerializationInfoEnumerator e = info.GetEnumerator ();
\r
148 while (e.MoveNext ())
\r
149 ow.WriteValue (writer, e.ObjectType, e.Value);
\r
152 public override bool RequiresTypes {
\r
153 get { return true; }
\r
157 class MemberTypeMetadata: ClrTypeMetadata
\r
159 MemberInfo[] members;
\r
161 public MemberTypeMetadata (Type type, StreamingContext context): base (type)
\r
163 members = FormatterServices.GetSerializableMembers (type, context);
\r
166 public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
\r
168 foreach (FieldInfo field in members)
\r
170 Type type = field.FieldType;
\r
171 while (type.IsArray)
\r
172 type = type.GetElementType();
\r
174 ow.WriteAssembly (writer, type.Assembly);
\r
178 public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
\r
180 writer.Write (members.Length);
\r
183 foreach (FieldInfo field in members)
\r
184 writer.Write (field.Name);
\r
188 foreach (FieldInfo field in members)
\r
189 ObjectWriter.WriteTypeCode (writer, field.FieldType);
\r
191 // Type specs of fields
\r
192 foreach (FieldInfo field in members)
\r
193 ow.WriteTypeSpec (writer, field.FieldType);
\r
197 public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
\r
199 object[] values = FormatterServices.GetObjectData (data, members);
\r
200 for (int n=0; n<values.Length; n++)
\r
201 ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);
\r
205 internal class ObjectWriter
\r
207 ObjectIDGenerator _idGenerator = new ObjectIDGenerator();
\r
208 Hashtable _cachedMetadata = new Hashtable();
\r
209 Queue _pendingObjects = new Queue();
\r
210 Hashtable _assemblyCache = new Hashtable();
\r
212 // Type metadata that can be shared with all serializers
\r
213 static Hashtable _cachedTypes = new Hashtable();
\r
215 internal static Assembly CorlibAssembly = typeof(string).Assembly;
\r
216 internal static string CorlibAssemblyName = typeof(string).Assembly.FullName;
\r
218 ISurrogateSelector _surrogateSelector;
\r
219 StreamingContext _context;
\r
220 FormatterAssemblyStyle _assemblyFormat;
\r
221 FormatterTypeStyle _typeFormat;
\r
223 int ArrayBufferLength = 4096;
\r
225 class MetadataReference
\r
227 public TypeMetadata Metadata;
\r
228 public long ObjectID;
\r
230 public MetadataReference (TypeMetadata metadata, long id)
\r
232 Metadata = metadata;
\r
237 public ObjectWriter (ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)
\r
239 _surrogateSelector = surrogateSelector;
\r
240 _context = context;
\r
241 _assemblyFormat = assemblyFormat;
\r
242 _typeFormat = typeFormat;
\r
245 public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)
\r
247 _pendingObjects.Clear();
\r
248 if (headers != null) QueueObject (headers);
\r
250 WriteQueuedObjects (writer);
\r
251 WriteSerializationEnd (writer);
\r
254 public void QueueObject (object obj)
\r
256 _pendingObjects.Enqueue (obj);
\r
259 public void WriteQueuedObjects (BinaryWriter writer)
\r
261 while (_pendingObjects.Count > 0)
\r
262 WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);
\r
265 public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)
\r
270 // If the object is a value type (not boxed) then there is no need
\r
271 // to register it in the id generator, because it won't have other
\r
272 // references to it
\r
274 if (isValueObject) id = _idGenerator.NextId;
\r
275 else id = _idGenerator.GetId (obj, out firstTime);
\r
277 if (obj is string) {
\r
278 WriteString (writer, id, (string)obj);
\r
280 else if (obj is Array) {
\r
281 WriteArray (writer, id, (Array)obj);
\r
284 WriteObject (writer, id, obj);
\r
287 public static void WriteSerializationEnd (BinaryWriter writer)
\r
289 writer.Write ((byte) BinaryElement.End);
\r
292 private void WriteObject (BinaryWriter writer, long id, object obj)
\r
295 TypeMetadata metadata;
\r
297 GetObjectData (obj, out metadata, out data);
\r
298 MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceTypeName];
\r
300 if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))
\r
302 // An object of the same type has already been serialized
\r
303 // It is not necessary to write again type metadata
\r
305 writer.Write ((byte) BinaryElement.RefTypeObject);
\r
306 writer.Write ((int)id);
\r
308 writer.Write ((int)metadataReference.ObjectID);
\r
309 metadata.WriteObjectData (this, writer, data);
\r
313 if (metadataReference == null)
\r
315 metadataReference = new MetadataReference (metadata, id);
\r
316 _cachedMetadata [metadata.InstanceTypeName] = metadataReference;
\r
319 bool writeTypes = metadata.RequiresTypes || _typeFormat == FormatterTypeStyle.TypesAlways;
\r
321 BinaryElement objectTag;
\r
324 if (metadata.TypeAssemblyName == CorlibAssemblyName)
\r
327 objectTag = writeTypes ? BinaryElement.RuntimeObject : BinaryElement.UntypedRuntimeObject;
\r
332 objectTag = writeTypes ? BinaryElement.ExternalObject : BinaryElement.UntypedExternalObject;
\r
333 assemblyId = WriteAssemblyName (writer, metadata.TypeAssemblyName);
\r
336 // Registers the assemblies needed for each field
\r
337 // If there are assemblies that where not registered before this object,
\r
340 metadata.WriteAssemblies (this, writer);
\r
342 // Writes the object
\r
344 writer.Write ((byte) objectTag);
\r
345 writer.Write ((int)id);
\r
346 writer.Write (metadata.InstanceTypeName);
\r
348 metadata.WriteTypeData (this, writer, writeTypes);
\r
349 if (assemblyId != -1) writer.Write (assemblyId);
\r
351 metadata.WriteObjectData (this, writer, data);
\r
354 private void GetObjectData (object obj, out TypeMetadata metadata, out object data)
\r
356 Type instanceType = obj.GetType();
\r
358 // Check if the formatter has a surrogate selector, if it does,
\r
359 // check if the surrogate selector handles objects of the given type.
\r
361 if (_surrogateSelector != null)
\r
363 ISurrogateSelector selector;
\r
364 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);
\r
365 if (surrogate != null)
\r
367 SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
\r
368 surrogate.GetObjectData (obj, info, _context);
\r
369 metadata = new SerializableTypeMetadata (instanceType, info);
\r
375 // Check if the object is marked with the Serializable attribute
\r
377 BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);
\r
379 ISerializable ser = obj as ISerializable;
\r
383 SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
\r
384 ser.GetObjectData (info, _context);
\r
385 metadata = new SerializableTypeMetadata (instanceType, info);
\r
391 if (_context.Context != null)
\r
393 // Don't cache metadata info when the Context property is not null sice
\r
394 // we can't control the number of possible contexts in this case
\r
395 metadata = new MemberTypeMetadata (instanceType, _context);
\r
399 Hashtable typesTable;
\r
400 bool isNew = false;
\r
401 lock (_cachedTypes) {
\r
402 typesTable = (Hashtable) _cachedTypes [_context.State];
\r
403 if (typesTable == null) {
\r
404 typesTable = new Hashtable ();
\r
405 _cachedTypes [_context.State] = typesTable;
\r
411 lock (typesTable) {
\r
413 metadata = (TypeMetadata) typesTable [instanceType];
\r
416 if (metadata == null) {
\r
417 metadata = CreateMemberTypeMetadata (instanceType);
\r
420 typesTable [instanceType] = metadata;
\r
425 TypeMetadata CreateMemberTypeMetadata (Type type)
\r
427 if (!BinaryCommon.UseReflectionSerialization) {
\r
428 Type metaType = CodeGenerator.GenerateMetadataType (type, _context);
\r
429 return (TypeMetadata) Activator.CreateInstance (metaType);
\r
432 return new MemberTypeMetadata (type, _context);
\r
435 private void WriteArray (BinaryWriter writer, long id, Array array)
\r
437 // There are 4 ways of serializing arrays:
\r
438 // The element GenericArray (7) can be used for all arrays.
\r
439 // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
\r
440 // arrays of primitive types
\r
441 // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
\r
442 // The element ArrayOfString (17) can be used for single-dimensional string arrays
\r
444 Type elementType = array.GetType().GetElementType();
\r
446 if (elementType == typeof (object) && array.Rank == 1) {
\r
447 WriteObjectArray (writer, id, array);
\r
449 else if (elementType == typeof (string) && array.Rank == 1) {
\r
450 WriteStringArray (writer, id, array);
\r
452 else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {
\r
453 WritePrimitiveTypeArray (writer, id, array);
\r
456 WriteGenericArray (writer, id, array);
\r
459 private void WriteGenericArray (BinaryWriter writer, long id, Array array)
\r
461 Type elementType = array.GetType().GetElementType();
\r
463 // Registers and writes the assembly of the array element type if needed
\r
465 if (!elementType.IsArray)
\r
466 WriteAssembly (writer, elementType.Assembly);
\r
468 // Writes the array
\r
470 writer.Write ((byte) BinaryElement.GenericArray);
\r
471 writer.Write ((int)id);
\r
473 // Write the structure of the array
\r
475 if (elementType.IsArray)
\r
476 writer.Write ((byte) ArrayStructure.Jagged);
\r
477 else if (array.Rank == 1)
\r
478 writer.Write ((byte) ArrayStructure.SingleDimensional);
\r
480 writer.Write ((byte) ArrayStructure.MultiDimensional);
\r
482 // Write the number of dimensions and the length
\r
483 // of each dimension
\r
485 writer.Write (array.Rank);
\r
486 for (int n=0; n<array.Rank; n++)
\r
487 writer.Write (array.GetUpperBound (n) + 1);
\r
490 WriteTypeCode (writer, elementType);
\r
491 WriteTypeSpec (writer, elementType);
\r
493 // Writes the values. For single-dimension array, a special tag is used
\r
494 // to represent multiple consecutive null values. I don't know why this
\r
495 // optimization is not used for multidimensional arrays.
\r
497 if (array.Rank == 1 && !elementType.IsValueType)
\r
499 WriteSingleDimensionArrayElements (writer, array, elementType);
\r
503 foreach (object item in array)
\r
504 WriteValue (writer, elementType, item);
\r
508 private void WriteObjectArray (BinaryWriter writer, long id, Array array)
\r
510 writer.Write ((byte) BinaryElement.ArrayOfObject);
\r
511 writer.Write ((int)id);
\r
512 writer.Write (array.Length); // Single dimension. Just write the length
\r
513 WriteSingleDimensionArrayElements (writer, array, typeof (object));
\r
516 private void WriteStringArray (BinaryWriter writer, long id, Array array)
\r
518 writer.Write ((byte) BinaryElement.ArrayOfString);
\r
519 writer.Write ((int)id);
\r
520 writer.Write (array.Length); // Single dimension. Just write the length
\r
521 WriteSingleDimensionArrayElements (writer, array, typeof (string));
\r
524 private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)
\r
526 writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);
\r
527 writer.Write ((int)id);
\r
528 writer.Write (array.Length); // Single dimension. Just write the length
\r
530 Type elementType = array.GetType().GetElementType();
\r
531 WriteTypeSpec (writer, elementType);
\r
533 switch (Type.GetTypeCode (elementType))
\r
535 case TypeCode.Boolean:
\r
536 foreach (bool item in (bool[]) array)
\r
537 writer.Write (item);
\r
540 case TypeCode.Byte:
\r
541 writer.Write ((byte[]) array);
\r
544 case TypeCode.Char:
\r
545 writer.Write ((char[]) array);
\r
548 case TypeCode.DateTime:
\r
549 foreach (DateTime item in (DateTime[]) array)
\r
550 writer.Write (item.Ticks);
\r
553 case TypeCode.Decimal:
\r
554 foreach (decimal item in (decimal[]) array)
\r
555 writer.Write (item);
\r
558 case TypeCode.Double:
559 if (array.Length > 2)
560 BlockWrite (writer, array, 8);
562 foreach (double item in (double[]) array)
563 writer.Write (item);
\r
566 case TypeCode.Int16:
\r
567 if (array.Length > 2)
568 BlockWrite (writer, array, 2);
570 foreach (short item in (short[]) array)
\r
571 writer.Write (item);
\r
575 if (array.Length > 2)
576 BlockWrite (writer, array, 4);
578 foreach (int item in (int[]) array)
\r
579 writer.Write (item);
\r
583 if (array.Length > 2)
584 BlockWrite (writer, array, 8);
586 foreach (long item in (long[]) array)
587 writer.Write (item);
\r
590 case TypeCode.SByte:
\r
591 if (array.Length > 2)
592 BlockWrite (writer, array, 1);
594 foreach (sbyte item in (sbyte[]) array)
\r
595 writer.Write (item);
\r
598 case TypeCode.Single:
\r
599 if (array.Length > 2)
600 BlockWrite (writer, array, 4);
602 foreach (float item in (float[]) array)
\r
603 writer.Write (item);
\r
606 case TypeCode.UInt16:
\r
607 if (array.Length > 2)
608 BlockWrite (writer, array, 2);
610 foreach (ushort item in (ushort[]) array)
\r
611 writer.Write (item);
\r
614 case TypeCode.UInt32:
\r
615 if (array.Length > 2)
616 BlockWrite (writer, array, 4);
618 foreach (uint item in (uint[]) array)
\r
619 writer.Write (item);
\r
622 case TypeCode.UInt64:
\r
623 if (array.Length > 2)
624 BlockWrite (writer, array, 8);
626 foreach (ulong item in (ulong[]) array)
\r
627 writer.Write (item);
\r
630 case TypeCode.String:
\r
631 foreach (string item in (string[]) array)
\r
632 writer.Write (item);
\r
636 if (elementType == typeof (TimeSpan)) {
\r
637 foreach (TimeSpan item in (TimeSpan[]) array)
\r
638 writer.Write (item.Ticks);
\r
641 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
\r
646 private void BlockWrite (BinaryWriter writer, Array array, int dataSize)
648 int totalSize = Buffer.ByteLength (array);
650 if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
651 arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
654 while (totalSize > 0) {
655 int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
656 Buffer.BlockCopy (array, pos, arrayBuffer, 0, size);
658 if (!BitConverter.IsLittleEndian && dataSize > 1)
659 BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
661 writer.Write (arrayBuffer, 0, size);
667 private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)
\r
670 foreach (object val in array)
\r
672 if (val != null && numNulls > 0)
\r
674 WriteNullFiller (writer, numNulls);
\r
675 WriteValue (writer, elementType, val);
\r
678 else if (val == null)
\r
681 WriteValue (writer, elementType, val);
\r
684 WriteNullFiller (writer, numNulls);
\r
687 private void WriteNullFiller (BinaryWriter writer, int numNulls)
\r
689 if (numNulls == 1) {
\r
690 writer.Write ((byte) BinaryElement.NullValue);
\r
692 else if (numNulls == 2) {
\r
693 writer.Write ((byte) BinaryElement.NullValue);
\r
694 writer.Write ((byte) BinaryElement.NullValue);
\r
696 else if (numNulls <= byte.MaxValue) {
\r
697 writer.Write ((byte) BinaryElement.ArrayFiller8b);
\r
698 writer.Write ((byte) numNulls);
\r
701 writer.Write ((byte) BinaryElement.ArrayFiller32b);
\r
702 writer.Write (numNulls);
\r
706 private void WriteObjectReference (BinaryWriter writer, long id)
\r
709 writer.Write ((byte) BinaryElement.ObjectReference);
\r
710 writer.Write ((int)id);
\r
713 public void WriteValue (BinaryWriter writer, Type valueType, object val)
\r
717 BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);
\r
718 writer.Write ((byte) BinaryElement.NullValue);
\r
720 else if (BinaryCommon.IsPrimitive(val.GetType()))
\r
722 if (!BinaryCommon.IsPrimitive(valueType))
\r
724 // It is a boxed primitive type value
\r
725 writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);
\r
726 WriteTypeSpec (writer, val.GetType());
\r
728 WritePrimitiveValue (writer, val);
\r
730 else if (valueType.IsValueType)
\r
732 // Value types are written embedded in the containing object
\r
733 WriteObjectInstance (writer, val, true);
\r
735 else if (val is string)
\r
737 // Strings are written embedded, unless already registered
\r
739 long id = _idGenerator.GetId (val, out firstTime);
\r
741 if (firstTime) WriteObjectInstance (writer, val, false);
\r
742 else WriteObjectReference (writer, id);
\r
746 // It is a reference type. Write a forward reference and queue the
\r
747 // object to the pending object list (unless already written).
\r
750 long id = _idGenerator.GetId (val, out firstTime);
\r
752 if (firstTime) _pendingObjects.Enqueue (val);
\r
753 WriteObjectReference (writer, id);
\r
757 private void WriteString (BinaryWriter writer, long id, string str)
\r
759 writer.Write ((byte) BinaryElement.String);
\r
760 writer.Write ((int)id);
\r
761 writer.Write (str);
\r
764 public int WriteAssembly (BinaryWriter writer, Assembly assembly)
\r
766 return WriteAssemblyName (writer, assembly.FullName);
\r
769 public int WriteAssemblyName (BinaryWriter writer, string assembly)
\r
771 if (assembly == ObjectWriter.CorlibAssemblyName) return -1;
\r
774 int id = RegisterAssembly (assembly, out firstTime);
\r
775 if (!firstTime) return id;
\r
777 writer.Write ((byte) BinaryElement.Assembly);
\r
779 if (_assemblyFormat == FormatterAssemblyStyle.Full)
\r
780 writer.Write (assembly);
\r
782 int i = assembly.IndexOf (',');
\r
783 if (i != -1) assembly = assembly.Substring (0, i);
\r
784 writer.Write (assembly);
\r
790 public int GetAssemblyId (Assembly assembly)
\r
792 return GetAssemblyNameId (assembly.FullName);
\r
795 public int GetAssemblyNameId (string assembly)
\r
797 return (int)_assemblyCache[assembly];
\r
800 private int RegisterAssembly (string assembly, out bool firstTime)
\r
802 if (_assemblyCache.ContainsKey (assembly))
\r
805 return (int)_assemblyCache[assembly];
\r
809 int id = (int)_idGenerator.GetId (0, out firstTime);
\r
810 _assemblyCache.Add (assembly, id);
\r
815 public static void WritePrimitiveValue (BinaryWriter writer, object value)
\r
817 Type type = value.GetType();
\r
819 switch (Type.GetTypeCode (type))
\r
821 case TypeCode.Boolean:
\r
822 writer.Write ((bool)value);
\r
825 case TypeCode.Byte:
\r
826 writer.Write ((byte) value);
\r
829 case TypeCode.Char:
\r
830 writer.Write ((char) value);
\r
833 case TypeCode.DateTime:
\r
834 writer.Write ( ((DateTime)value).Ticks);
\r
837 case TypeCode.Decimal:
\r
838 writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));
\r
841 case TypeCode.Double:
\r
842 writer.Write ((double) value);
\r
845 case TypeCode.Int16:
\r
846 writer.Write ((short) value);
\r
849 case TypeCode.Int32:
\r
850 writer.Write ((int) value);
\r
853 case TypeCode.Int64:
\r
854 writer.Write ((long) value);
\r
857 case TypeCode.SByte:
\r
858 writer.Write ((sbyte) value);
\r
861 case TypeCode.Single:
\r
862 writer.Write ((float) value);
\r
865 case TypeCode.UInt16:
\r
866 writer.Write ((ushort) value);
\r
869 case TypeCode.UInt32:
\r
870 writer.Write ((uint) value);
\r
873 case TypeCode.UInt64:
\r
874 writer.Write ((ulong) value);
\r
877 case TypeCode.String:
\r
878 writer.Write ((string) value);
\r
882 if (type == typeof (TimeSpan))
\r
883 writer.Write (((TimeSpan)value).Ticks);
\r
885 throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);
\r
890 public static void WriteTypeCode (BinaryWriter writer, Type type)
\r
892 writer.Write ((byte) GetTypeTag (type));
\r
895 public static TypeTag GetTypeTag (Type type)
\r
897 if (type == typeof (string)) {
\r
898 return TypeTag.String;
\r
900 else if (BinaryCommon.IsPrimitive (type)) {
\r
901 return TypeTag.PrimitiveType;
\r
903 else if (type == typeof (object)) {
\r
904 return TypeTag.ObjectType;
\r
906 else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {
\r
907 return TypeTag.ArrayOfObject;
\r
909 else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){
\r
910 return TypeTag.ArrayOfString;
\r
912 else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {
\r
913 return TypeTag.ArrayOfPrimitiveType;
\r
915 else if (type.Assembly == CorlibAssembly) {
\r
916 return TypeTag.RuntimeType;
\r
919 return TypeTag.GenericType;
\r
922 public void WriteTypeSpec (BinaryWriter writer, Type type)
\r
924 // WARNING Keep in sync with EmitWriteTypeSpec
\r
926 switch (GetTypeTag (type))
\r
928 case TypeTag.PrimitiveType:
\r
929 writer.Write (BinaryCommon.GetTypeCode (type));
\r
932 case TypeTag.RuntimeType:
\r
933 writer.Write (type.FullName);
\r
936 case TypeTag.GenericType:
\r
937 writer.Write (type.FullName);
\r
938 writer.Write ((int)GetAssemblyId (type.Assembly));
\r
941 case TypeTag.ArrayOfPrimitiveType:
\r
942 writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));
\r
946 // Type spec not needed
\r