Jo Shields 3c1f479b9d Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
2015-04-07 09:35:12 +01:00

995 lines
27 KiB
C#

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