4 // Lluis Sanchez Gual (lluis@ideary.com)
\r
6 // (C) 2003 Lluis Sanchez Gual
\r
10 using System.Collections;
\r
11 using System.Runtime.Serialization;
\r
12 using System.Runtime.Remoting.Messaging;
\r
13 using System.Reflection;
\r
14 using System.Globalization;
\r
16 namespace System.Runtime.Serialization.Formatters.Binary
\r
18 abstract class TypeMetadata
\r
20 public TypeMetadata (Type instanceType)
\r
22 InstanceType = instanceType;
\r
23 TypeAssembly = instanceType.Assembly;
\r
26 public Assembly TypeAssembly;
\r
27 public Type InstanceType;
\r
29 public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);
\r
30 public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer);
\r
31 public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);
\r
33 public virtual bool IsCompatible (TypeMetadata other)
\r
39 class SerializableTypeMetadata: TypeMetadata
\r
44 public SerializableTypeMetadata (Type itype, SerializationInfo info): base (itype)
\r
46 types = new Type [info.MemberCount];
\r
47 names = new string [info.MemberCount];
\r
49 SerializationInfoEnumerator e = info.GetEnumerator ();
\r
52 while (e.MoveNext ())
\r
54 types[n] = e.ObjectType;
\r
59 if (info.FullTypeName != InstanceType.FullName || info.AssemblyName != TypeAssembly.FullName)
\r
61 TypeAssembly = Assembly.Load (info.AssemblyName);
\r
62 InstanceType = TypeAssembly.GetType (info.FullTypeName);
\r
66 public override bool IsCompatible (TypeMetadata other)
\r
68 if (!(other is SerializableTypeMetadata)) return false;
\r
70 SerializableTypeMetadata tm = (SerializableTypeMetadata)other;
\r
71 if (types.Length != tm.types.Length) return false;
\r
72 if (TypeAssembly != tm.TypeAssembly) return false;
\r
73 if (InstanceType != tm.InstanceType) return false;
\r
74 for (int n=0; n<types.Length; n++)
\r
76 if (types[n] != tm.types[n]) return false;
\r
77 if (names[n] != tm.names[n]) return false;
\r
82 public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
\r
84 foreach (Type mtype in types)
\r
87 while (type.IsArray)
\r
88 type = type.GetElementType();
\r
90 ow.WriteAssembly (writer, type.Assembly);
\r
94 public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer)
\r
96 writer.Write (types.Length);
\r
99 foreach (string name in names)
\r
100 writer.Write (name);
\r
103 foreach (Type type in types)
\r
104 ObjectWriter.WriteTypeCode (writer, type);
\r
106 // Type specs of fields
\r
107 foreach (Type type in types)
\r
108 ow.WriteTypeSpec (writer, type);
\r
111 public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
\r
113 SerializationInfo info = (SerializationInfo) data;
\r
114 SerializationInfoEnumerator e = info.GetEnumerator ();
\r
116 while (e.MoveNext ())
\r
117 ow.WriteValue (writer, e.ObjectType, e.Value);
\r
121 class MemberTypeMetadata: TypeMetadata
\r
123 MemberInfo[] members;
\r
125 public MemberTypeMetadata (Type type, StreamingContext context): base (type)
\r
127 members = FormatterServices.GetSerializableMembers (type, context);
\r
130 public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
\r
132 foreach (FieldInfo field in members)
\r
134 Type type = field.FieldType;
\r
135 while (type.IsArray)
\r
136 type = type.GetElementType();
\r
138 ow.WriteAssembly (writer, type.Assembly);
\r
142 public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer)
\r
144 writer.Write (members.Length);
\r
147 foreach (FieldInfo field in members) {
\r
148 if (field.DeclaringType == InstanceType)
\r
149 writer.Write (field.Name);
\r
151 writer.Write (field.DeclaringType.Name + "+" + field.Name);
\r
155 foreach (FieldInfo field in members)
\r
156 ObjectWriter.WriteTypeCode (writer, field.FieldType);
\r
158 // Type specs of fields
\r
159 foreach (FieldInfo field in members)
\r
160 ow.WriteTypeSpec (writer, field.FieldType);
\r
163 public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
\r
165 object[] values = FormatterServices.GetObjectData (data, members);
\r
166 for (int n=0; n<values.Length; n++)
\r
167 ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);
\r
171 internal class ObjectWriter
\r
173 ObjectIDGenerator _idGenerator = new ObjectIDGenerator();
\r
174 Hashtable _cachedMetadata = new Hashtable();
\r
175 Queue _pendingObjects = new Queue();
\r
176 Hashtable _assemblyCache = new Hashtable();
\r
178 // Type metadata that can be shared with all serializers
\r
179 static Hashtable _cachedTypes = new Hashtable();
\r
181 internal static Assembly CorlibAssembly = typeof(string).Assembly;
\r
183 ISurrogateSelector _surrogateSelector;
\r
184 StreamingContext _context;
\r
185 FormatterAssemblyStyle _assemblyFormat;
\r
187 class MetadataReference
\r
189 public TypeMetadata Metadata;
\r
190 public long ObjectID;
\r
192 public MetadataReference (TypeMetadata metadata, long id)
\r
194 Metadata = metadata;
\r
199 public ObjectWriter (ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat)
\r
201 _surrogateSelector = surrogateSelector;
\r
202 _context = context;
\r
203 _assemblyFormat = assemblyFormat;
\r
206 public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)
\r
208 _pendingObjects.Clear();
\r
209 if (headers != null) QueueObject (headers);
\r
211 WriteQueuedObjects (writer);
\r
212 WriteSerializationEnd (writer);
\r
215 public void QueueObject (object obj)
\r
217 _pendingObjects.Enqueue (obj);
\r
220 public void WriteQueuedObjects (BinaryWriter writer)
\r
223 while (_pendingObjects.Count > 0)
\r
224 WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);
\r
227 public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)
\r
232 // If the object is a value type (not boxed) then there is no need
\r
233 // to register it in the id generator, because it won't have other
\r
234 // references to it
\r
236 if (isValueObject) id = _idGenerator.NextId;
\r
237 else id = _idGenerator.GetId (obj, out firstTime);
\r
239 if (obj is string) {
\r
240 WriteString (writer, id, (string)obj);
\r
242 else if (obj is Array) {
\r
243 WriteArray (writer, id, (Array)obj);
\r
246 WriteObject (writer, id, obj);
\r
249 public static void WriteSerializationEnd (BinaryWriter writer)
\r
251 writer.Write ((byte) BinaryElement.End);
\r
254 private void WriteObject (BinaryWriter writer, long id, object obj)
\r
257 TypeMetadata metadata;
\r
259 GetObjectData (obj, out metadata, out data);
\r
260 MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceType];
\r
262 if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))
\r
264 // An object of the same type has already been serialized
\r
265 // It is not necessary to write again type metadata
\r
267 writer.Write ((byte) BinaryElement.RefTypeObject);
\r
268 writer.Write ((int)id);
\r
270 writer.Write ((int)metadataReference.ObjectID);
\r
271 metadata.WriteObjectData (this, writer, data);
\r
275 if (metadataReference == null)
\r
277 metadataReference = new MetadataReference (metadata, id);
\r
278 _cachedMetadata [metadata.InstanceType] = metadataReference;
\r
281 BinaryElement objectTag;
\r
284 if (metadata.TypeAssembly == CorlibAssembly)
\r
287 objectTag = BinaryElement.RuntimeObject;
\r
292 objectTag = BinaryElement.ExternalObject;
\r
293 assemblyId = WriteAssembly (writer, metadata.TypeAssembly);
\r
296 // Registers the assemblies needed for each field
\r
297 // If there are assemblies that where not registered before this object,
\r
300 metadata.WriteAssemblies (this, writer);
\r
302 // Writes the object
\r
304 writer.Write ((byte) objectTag);
\r
305 writer.Write ((int)id);
\r
306 writer.Write (metadata.InstanceType.FullName);
\r
308 metadata.WriteTypeData (this, writer);
\r
309 if (assemblyId != -1) writer.Write (assemblyId);
\r
311 metadata.WriteObjectData (this, writer, data);
\r
314 private void GetObjectData (object obj, out TypeMetadata metadata, out object data)
\r
316 Type instanceType = obj.GetType();
\r
318 // Check if the formatter has a surrogate selector
\96 if it does,
\r
319 // check if the surrogate selector handles objects of the given type.
\r
321 if (_surrogateSelector != null)
\r
323 ISurrogateSelector selector;
\r
324 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);
\r
325 if (surrogate != null)
\r
327 SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
\r
328 surrogate.GetObjectData (obj, info, _context);
\r
329 metadata = new SerializableTypeMetadata (instanceType, info);
\r
335 // Check if the object is marked with the Serializable attribute
\r
337 if (!instanceType.IsSerializable)
\r
338 throw new SerializationException ("Type " + instanceType +
\r
339 " is not marked as Serializable " +
\r
340 "and does not implement ISerializable.");
\r
342 ISerializable ser = obj as ISerializable;
\r
346 SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
\r
347 ser.GetObjectData (info, _context);
\r
348 metadata = new SerializableTypeMetadata (instanceType, info);
\r
354 if (_context.Context != null)
\r
356 // Don't cache metadata info when the Context property is not null sice
\r
357 // we can't control the number of possible contexts in this case
\r
358 metadata = new MemberTypeMetadata (instanceType, _context);
\r
363 lock (_cachedTypes)
\r
365 Hashtable typesTable = (Hashtable) _cachedTypes [_context.State];
\r
366 if (typesTable != null)
\r
368 metadata = (TypeMetadata) typesTable [instanceType];
\r
369 if (metadata == null)
\r
371 metadata = CreateMemberTypeMetadata (instanceType);
\r
372 typesTable [instanceType] = metadata;
\r
377 metadata = CreateMemberTypeMetadata (instanceType);
\r
378 typesTable = new Hashtable ();
\r
379 typesTable [instanceType] = metadata;
\r
380 _cachedTypes [_context.State] = typesTable;
\r
386 TypeMetadata CreateMemberTypeMetadata (Type type)
\r
388 if (!BinaryCommon.UseReflectionSerialization) {
\r
389 Type metaType = CodeGenerator.GenerateMetadataType (type, _context);
\r
390 return (TypeMetadata) Activator.CreateInstance (metaType);
\r
393 return new MemberTypeMetadata (type, _context);
\r
396 private void WriteArray (BinaryWriter writer, long id, Array array)
\r
398 // There are 4 ways of serializing arrays:
\r
399 // The element GenericArray (7) can be used for all arrays.
\r
400 // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
\r
401 // arrays of primitive types
\r
402 // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
\r
403 // The element ArrayOfString (17) can be used for single-dimensional string arrays
\r
405 Type elementType = array.GetType().GetElementType();
\r
407 if (elementType == typeof (object) && array.Rank == 1) {
\r
408 WriteObjectArray (writer, id, array);
\r
410 else if (elementType == typeof (string) && array.Rank == 1) {
\r
411 WriteStringArray (writer, id, array);
\r
413 else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {
\r
414 WritePrimitiveTypeArray (writer, id, array);
\r
417 WriteGenericArray (writer, id, array);
\r
420 private void WriteGenericArray (BinaryWriter writer, long id, Array array)
\r
422 Type elementType = array.GetType().GetElementType();
\r
424 // Registers and writes the assembly of the array element type if needed
\r
426 if (!elementType.IsArray)
\r
427 WriteAssembly (writer, elementType.Assembly);
\r
429 // Writes the array
\r
431 writer.Write ((byte) BinaryElement.GenericArray);
\r
432 writer.Write ((int)id);
\r
434 // Write the structure of the array
\r
436 if (elementType.IsArray)
\r
437 writer.Write ((byte) ArrayStructure.Jagged);
\r
438 else if (array.Rank == 1)
\r
439 writer.Write ((byte) ArrayStructure.SingleDimensional);
\r
441 writer.Write ((byte) ArrayStructure.MultiDimensional);
\r
443 // Write the number of dimensions and the length
\r
444 // of each dimension
\r
446 writer.Write (array.Rank);
\r
447 for (int n=0; n<array.Rank; n++)
\r
448 writer.Write (array.GetUpperBound (n) + 1);
\r
451 WriteTypeCode (writer, elementType);
\r
452 WriteTypeSpec (writer, elementType);
\r
454 // Writes the values. For single-dimension array, a special tag is used
\r
455 // to represent multiple consecutive null values. I don't know why this
\r
456 // optimization is not used for multidimensional arrays.
\r
458 if (array.Rank == 1 && !elementType.IsValueType)
\r
460 WriteSingleDimensionArrayElements (writer, array, elementType);
\r
464 int[] indices = new int[array.Rank];
\r
466 // Initialize indexes
\r
467 for (int dim = array.Rank-1; dim >= 0; dim--)
\r
468 indices[dim] = array.GetLowerBound (dim);
\r
473 WriteValue (writer, elementType, array.GetValue (indices));
\r
475 for (int dim = array.Rank-1; dim >= 0; dim--)
\r
478 if (indices[dim] > array.GetUpperBound (dim))
\r
481 indices[dim] = array.GetLowerBound (dim);
\r
482 continue; // Increment the next dimension's index
\r
484 end = true; // That was the last dimension. Finished.
\r
492 private void WriteObjectArray (BinaryWriter writer, long id, Array array)
\r
494 writer.Write ((byte) BinaryElement.ArrayOfObject);
\r
495 writer.Write ((int)id);
\r
496 writer.Write (array.Length); // Single dimension. Just write the length
\r
497 WriteSingleDimensionArrayElements (writer, array, typeof (object));
\r
500 private void WriteStringArray (BinaryWriter writer, long id, Array array)
\r
502 writer.Write ((byte) BinaryElement.ArrayOfString);
\r
503 writer.Write ((int)id);
\r
504 writer.Write (array.Length); // Single dimension. Just write the length
\r
505 WriteSingleDimensionArrayElements (writer, array, typeof (string));
\r
508 private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)
\r
510 writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);
\r
511 writer.Write ((int)id);
\r
512 writer.Write (array.Length); // Single dimension. Just write the length
\r
514 Type elementType = array.GetType().GetElementType();
\r
515 WriteTypeSpec (writer, elementType);
\r
517 switch (Type.GetTypeCode (elementType))
\r
519 case TypeCode.Boolean:
\r
520 foreach (bool item in (bool[]) array)
\r
521 writer.Write (item);
\r
524 case TypeCode.Byte:
\r
525 writer.Write ((byte[]) array);
\r
528 case TypeCode.Char:
\r
529 foreach (char item in (char[]) array)
\r
530 writer.Write (item);
\r
533 case TypeCode.DateTime:
\r
534 foreach (DateTime item in (DateTime[]) array)
\r
535 writer.Write (item.Ticks);
\r
538 case TypeCode.Decimal:
\r
539 foreach (decimal item in (decimal[]) array)
\r
540 writer.Write (item);
\r
543 case TypeCode.Double:
\r
544 foreach (double item in (double[]) array)
\r
545 writer.Write (item);
\r
548 case TypeCode.Int16:
\r
549 foreach (short item in (short[]) array)
\r
550 writer.Write (item);
\r
553 case TypeCode.Int32:
\r
554 foreach (int item in (int[]) array)
\r
555 writer.Write (item);
\r
558 case TypeCode.Int64:
\r
559 foreach (long item in (long[]) array)
\r
560 writer.Write (item);
\r
563 case TypeCode.SByte:
\r
564 foreach (sbyte item in (sbyte[]) array)
\r
565 writer.Write (item);
\r
568 case TypeCode.Single:
\r
569 foreach (float item in (float[]) array)
\r
570 writer.Write (item);
\r
573 case TypeCode.UInt16:
\r
574 foreach (ushort item in (ushort[]) array)
\r
575 writer.Write (item);
\r
578 case TypeCode.UInt32:
\r
579 foreach (uint item in (uint[]) array)
\r
580 writer.Write (item);
\r
583 case TypeCode.UInt64:
\r
584 foreach (ulong item in (ulong[]) array)
\r
585 writer.Write (item);
\r
588 case TypeCode.String:
\r
589 foreach (string item in (string[]) array)
\r
590 writer.Write (item);
\r
594 if (elementType == typeof (TimeSpan)) {
\r
595 foreach (TimeSpan item in (TimeSpan[]) array)
\r
596 writer.Write (item.Ticks);
\r
599 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
\r
604 private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)
\r
607 for (int n = array.GetLowerBound (0); n<=array.GetUpperBound(0); n++)
\r
609 object val = array.GetValue (n);
\r
610 if (val != null && numNulls > 0)
\r
612 WriteNullFiller (writer, numNulls);
\r
613 WriteValue (writer, elementType, val);
\r
616 else if (val == null)
\r
619 WriteValue (writer, elementType, val);
\r
622 WriteNullFiller (writer, numNulls);
\r
625 private void WriteNullFiller (BinaryWriter writer, int numNulls)
\r
627 if (numNulls == 1) {
\r
628 writer.Write ((byte) BinaryElement.NullValue);
\r
630 else if (numNulls == 2) {
\r
631 writer.Write ((byte) BinaryElement.NullValue);
\r
632 writer.Write ((byte) BinaryElement.NullValue);
\r
634 else if (numNulls <= byte.MaxValue) {
\r
635 writer.Write ((byte) BinaryElement.ArrayFiller8b);
\r
636 writer.Write ((byte) numNulls);
\r
639 writer.Write ((byte) BinaryElement.ArrayFiller32b);
\r
640 writer.Write (numNulls);
\r
644 private void WriteObjectReference (BinaryWriter writer, long id)
\r
647 writer.Write ((byte) BinaryElement.ObjectReference);
\r
648 writer.Write ((int)id);
\r
651 public void WriteValue (BinaryWriter writer, Type valueType, object val)
\r
655 writer.Write ((byte) BinaryElement.NullValue);
\r
657 else if (BinaryCommon.IsPrimitive(val.GetType()))
\r
659 if (!BinaryCommon.IsPrimitive(valueType))
\r
661 // It is a boxed primitive type value
\r
662 writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);
\r
663 WriteTypeSpec (writer, val.GetType());
\r
665 WritePrimitiveValue (writer, val);
\r
667 else if (valueType.IsValueType)
\r
669 // Value types are written embedded in the containing object
\r
670 WriteObjectInstance (writer, val, true);
\r
672 else if (val is string)
\r
674 // Strings are written embedded, unless already registered
\r
676 long id = _idGenerator.GetId (val, out firstTime);
\r
678 if (firstTime) WriteObjectInstance (writer, val, false);
\r
679 else WriteObjectReference (writer, id);
\r
683 // It is a reference type. Write a forward reference and queue the
\r
684 // object to the pending object list (unless already written).
\r
687 long id = _idGenerator.GetId (val, out firstTime);
\r
689 if (firstTime) _pendingObjects.Enqueue (val);
\r
690 WriteObjectReference (writer, id);
\r
694 private void WriteString (BinaryWriter writer, long id, string str)
\r
696 writer.Write ((byte) BinaryElement.String);
\r
697 writer.Write ((int)id);
\r
698 writer.Write (str);
\r
701 public int WriteAssembly (BinaryWriter writer, Assembly assembly)
\r
703 if (assembly == ObjectWriter.CorlibAssembly) return -1;
\r
706 int id = RegisterAssembly (assembly, out firstTime);
\r
707 if (!firstTime) return id;
\r
709 writer.Write ((byte) BinaryElement.Assembly);
\r
711 if (_assemblyFormat == FormatterAssemblyStyle.Full)
\r
712 writer.Write (assembly.GetName ().FullName);
\r
714 writer.Write (assembly.GetName ().Name);
\r
719 public int GetAssemblyId (Assembly assembly)
\r
721 return (int)_assemblyCache[assembly];
\r
724 private int RegisterAssembly (Assembly assembly, out bool firstTime)
\r
726 if (_assemblyCache.ContainsKey (assembly))
\r
729 return (int)_assemblyCache[assembly];
\r
733 int id = (int)_idGenerator.GetId (0, out firstTime);
\r
734 _assemblyCache.Add (assembly, id);
\r
739 public static void WritePrimitiveValue (BinaryWriter writer, object value)
\r
741 Type type = value.GetType();
\r
743 switch (Type.GetTypeCode (type))
\r
745 case TypeCode.Boolean:
\r
746 writer.Write ((bool)value);
\r
749 case TypeCode.Byte:
\r
750 writer.Write ((byte) value);
\r
753 case TypeCode.Char:
\r
754 writer.Write ((char) value);
\r
757 case TypeCode.DateTime:
\r
758 writer.Write ( ((DateTime)value).Ticks);
\r
761 case TypeCode.Decimal:
\r
762 writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));
\r
765 case TypeCode.Double:
\r
766 writer.Write ((double) value);
\r
769 case TypeCode.Int16:
\r
770 writer.Write ((short) value);
\r
773 case TypeCode.Int32:
\r
774 writer.Write ((int) value);
\r
777 case TypeCode.Int64:
\r
778 writer.Write ((long) value);
\r
781 case TypeCode.SByte:
\r
782 writer.Write ((sbyte) value);
\r
785 case TypeCode.Single:
\r
786 writer.Write ((float) value);
\r
789 case TypeCode.UInt16:
\r
790 writer.Write ((ushort) value);
\r
793 case TypeCode.UInt32:
\r
794 writer.Write ((uint) value);
\r
797 case TypeCode.UInt64:
\r
798 writer.Write ((ulong) value);
\r
801 case TypeCode.String:
\r
802 writer.Write ((string) value);
\r
806 if (type == typeof (TimeSpan))
\r
807 writer.Write (((TimeSpan)value).Ticks);
\r
809 throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);
\r
814 public static void WriteTypeCode (BinaryWriter writer, Type type)
\r
816 writer.Write ((byte) GetTypeTag (type));
\r
819 public static TypeTag GetTypeTag (Type type)
\r
821 if (type == typeof (string)) {
\r
822 return TypeTag.String;
\r
824 else if (BinaryCommon.IsPrimitive (type)) {
\r
825 return TypeTag.PrimitiveType;
\r
827 else if (type == typeof (object)) {
\r
828 return TypeTag.ObjectType;
\r
830 else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {
\r
831 return TypeTag.ArrayOfObject;
\r
833 else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){
\r
834 return TypeTag.ArrayOfString;
\r
836 else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {
\r
837 return TypeTag.ArrayOfPrimitiveType;
\r
839 else if (type.Assembly == CorlibAssembly) {
\r
840 return TypeTag.RuntimeType;
\r
843 return TypeTag.GenericType;
\r
846 public void WriteTypeSpec (BinaryWriter writer, Type type)
\r
848 // WARNING Keep in sync with EmitWriteTypeSpec
\r
850 switch (GetTypeTag (type))
\r
852 case TypeTag.PrimitiveType:
\r
853 writer.Write (BinaryCommon.GetTypeCode (type));
\r
856 case TypeTag.RuntimeType:
\r
857 writer.Write (type.FullName);
\r
860 case TypeTag.GenericType:
\r
861 writer.Write (type.FullName);
\r
862 writer.Write ((int)GetAssemblyId (type.Assembly));
\r
865 case TypeTag.ArrayOfPrimitiveType:
\r
866 writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));
\r
870 // Type spec not needed
\r