/// <summary> /// Write enum value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="val">Enum value.</param> public void WriteEnum <T>(T val) { // ReSharper disable once CompareNonConstrainedGenericWithNull if (val == null) { WriteNullField(); } else { // Unwrap nullable. var valType = val.GetType(); var type = Nullable.GetUnderlyingType(valType) ?? valType; if (!type.IsEnum) { throw new BinaryObjectException("Type is not an enum: " + type); } var handler = BinarySystemHandlers.GetWriteHandler(type); if (handler != null) { // All enums except long/ulong. handler.Write(this, val); } else { throw new BinaryObjectException(string.Format("Enum '{0}' has unsupported underlying type '{1}'. " + "Use WriteObject instead of WriteEnum.", type, Enum.GetUnderlyingType(type))); } } }
/// <summary> /// Check whether the given object is binarizeble, i.e. it can be serialized with binary marshaller. /// </summary> /// <param name="obj">Object.</param> /// <returns>True if binarizable.</returns> internal bool IsBinarizable(object obj) { if (obj != null) { Type type = obj.GetType(); // We assume object as binarizable only in case it has descriptor. // Collections, Enums and non-primitive arrays do not have descriptors // and this is fine here because we cannot know whether their members are binarizable. return(_marsh.GetDescriptor(type) != null || BinarySystemHandlers.GetWriteHandler(type) != null); } return(true); }
/// <summary> /// Deserialize object. /// </summary> /// <param name="res">Deserialized object.</param> /// <param name="typeOverride">The type override. /// There can be multiple versions of the same type when peer assembly loading is enabled. /// Only first one is registered in Marshaller. /// This parameter specifies exact type to be instantiated.</param> /// <returns> /// Deserialized object. /// </returns> public bool TryDeserialize <T>(out T res, Type typeOverride = null) { int pos = Stream.Position; byte hdr = Stream.ReadByte(); var doDetach = _detach; // save detach flag into a var and reset so it does not go deeper _detach = false; switch (hdr) { case BinaryUtils.HdrNull: res = default(T); return(false); case BinaryUtils.HdrHnd: res = ReadHandleObject <T>(pos, typeOverride); return(true); case BinaryUtils.HdrFull: res = ReadFullObject <T>(pos, typeOverride); return(true); case BinaryUtils.TypeBinary: res = ReadBinaryObject <T>(doDetach); return(true); case BinaryUtils.TypeEnum: res = ReadEnum0 <T>(this, _mode == BinaryMode.ForceBinary); return(true); case BinaryUtils.TypeBinaryEnum: res = ReadEnum0 <T>(this, _mode != BinaryMode.Deserialize); return(true); } if (BinarySystemHandlers.TryReadSystemType(hdr, this, out res)) { return(true); } throw new BinaryObjectException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']'); }
/// <summary> /// Deserialize object. /// </summary> /// <returns>Deserialized object.</returns> public bool TryDeserialize <T>(out T res) { int pos = Stream.Position; byte hdr = Stream.ReadByte(); var doDetach = _detach; // save detach flag into a var and reset so it does not go deeper _detach = false; switch (hdr) { case BinaryUtils.HdrNull: res = default(T); return(false); case BinaryUtils.HdrHnd: res = ReadHandleObject <T>(pos); return(true); case BinaryUtils.HdrFull: res = ReadFullObject <T>(pos); return(true); case BinaryUtils.TypeBinary: res = ReadBinaryObject <T>(doDetach); return(true); } if (BinaryUtils.IsPredefinedType(hdr)) { res = BinarySystemHandlers.ReadSystemType <T>(hdr, this); return(true); } throw new BinaryObjectException("Invalid header on deserialization [pos=" + pos + ", hdr=" + hdr + ']'); }
/// <summary> /// Write object. /// </summary> /// <param name="obj">Object.</param> public void Write <T>(T obj) { // Handle special case for null. // ReSharper disable once CompareNonConstrainedGenericWithNull if (obj == null) { _stream.WriteByte(BinaryUtils.HdrNull); return; } // We use GetType() of a real object instead of typeof(T) to take advantage of // automatic Nullable'1 unwrapping. Type type = obj.GetType(); // Handle common case when primitive is written. if (type.IsPrimitive) { WritePrimitive(obj, type); return; } // Handle special case for builder. if (WriteBuilderSpecials(obj)) { return; } // Are we dealing with a well-known type? var handler = BinarySystemHandlers.GetWriteHandler(type); if (handler != null) { if (handler.SupportsHandles && WriteHandle(_stream.Position, obj)) { return; } handler.Write(this, obj); return; } // Wrap objects as required. if (WrapperFunc != null && type != WrapperFunc.Method.ReturnType) { if (_isInWrapper) { _isInWrapper = false; } else { _isInWrapper = true; Write(WrapperFunc(obj)); return; } } // Suppose that we faced normal object and perform descriptor lookup. var desc = _marsh.GetDescriptor(type); // Writing normal object. var pos = _stream.Position; // Dealing with handles. if (desc.Serializer.SupportsHandles && WriteHandle(pos, obj)) { return; } // Skip header length as not everything is known now _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); // Write type name for unregistered types if (!desc.IsRegistered) { WriteString(Marshaller.GetTypeName(type)); } var headerSize = _stream.Position - pos; // Preserve old frame. var oldFrame = _frame; // Push new frame. _frame.RawPos = 0; _frame.Pos = pos; _frame.Struct = new BinaryStructureTracker(desc, desc.WriterTypeStructure); _frame.HasCustomTypeData = false; var schemaIdx = _schema.PushSchema(); try { // Write object fields. desc.Serializer.WriteBinary(obj, this); var dataEnd = _stream.Position; // Write schema var schemaOffset = dataEnd - pos; int schemaId; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; if (_frame.HasCustomTypeData) { flags |= BinaryObjectHeader.Flag.CustomDotNetType; } if (Marshaller.CompactFooter && desc.UserType) { flags |= BinaryObjectHeader.Flag.CompactFooter; } var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags); if (hasSchema) { flags |= BinaryObjectHeader.Flag.HasSchema; // Calculate and write header. if (_frame.RawPos > 0) { _stream.WriteInt(_frame.RawPos - pos); // raw offset is in the last 4 bytes } // Update schema in type descriptor if (desc.Schema.Get(schemaId) == null) { desc.Schema.Add(schemaId, _schema.GetSchema(schemaIdx)); } } else { schemaOffset = headerSize; } if (_frame.RawPos > 0) { flags |= BinaryObjectHeader.Flag.HasRaw; } var len = _stream.Position - pos; var hashCode = BinaryArrayEqualityComparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size, dataEnd - pos - BinaryObjectHeader.Size); var header = new BinaryObjectHeader(desc.IsRegistered ? desc.TypeId : BinaryTypeId.Unregistered, hashCode, len, schemaId, schemaOffset, flags); BinaryObjectHeader.Write(header, _stream, pos); Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end } finally { _schema.PopSchema(schemaIdx); } // Apply structure updates if any. _frame.Struct.UpdateWriterStructure(this); // Restore old frame. _frame = oldFrame; }
/// <summary> /// Write object. /// </summary> /// <param name="obj">Object.</param> public void Write <T>(T obj) { // Handle special case for null. if (obj == null) { _stream.WriteByte(BinaryUtils.HdrNull); return; } // We use GetType() of a real object instead of typeof(T) to take advantage of // automatic Nullable'1 unwrapping. Type type = obj.GetType(); // Handle common case when primitive is written. if (type.IsPrimitive) { WritePrimitive(obj, type); return; } // Handle special case for builder. if (WriteBuilderSpecials(obj)) { return; } // Suppose that we faced normal object and perform descriptor lookup. IBinaryTypeDescriptor desc = type.IsEnum ? null : _marsh.GetDescriptor(type); if (desc != null) { // Writing normal object. var pos = _stream.Position; // Dealing with handles. if (!(desc.Serializer is IBinarySystemTypeSerializer) && WriteHandle(pos, obj)) { return; } // Skip header length as not everything is known now _stream.Seek(BinaryObjectHeader.Size, SeekOrigin.Current); // Preserve old frame. int oldTypeId = _curTypeId; IBinaryNameMapper oldConverter = _curConverter; IBinaryIdMapper oldMapper = _curMapper; int oldRawPos = _curRawPos; var oldPos = _curPos; var oldStruct = _curStruct; // Push new frame. _curTypeId = desc.TypeId; _curConverter = desc.NameMapper; _curMapper = desc.IdMapper; _curRawPos = 0; _curPos = pos; _curStruct = new BinaryStructureTracker(desc, desc.WriterTypeStructure); var schemaIdx = _schema.PushSchema(); try { // Write object fields. desc.Serializer.WriteBinary(obj, this); // Write schema var schemaOffset = _stream.Position - pos; int schemaId; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; var hasSchema = _schema.WriteSchema(_stream, schemaIdx, out schemaId, ref flags); if (hasSchema) { flags |= BinaryObjectHeader.Flag.HasSchema; // Calculate and write header. if (_curRawPos > 0) { _stream.WriteInt(_curRawPos - pos); // raw offset is in the last 4 bytes } } else { schemaOffset = BinaryObjectHeader.Size; } if (_curRawPos > 0) { flags |= BinaryObjectHeader.Flag.HasRaw; } var len = _stream.Position - pos; var header = new BinaryObjectHeader(desc.TypeId, obj.GetHashCode(), len, schemaId, schemaOffset, flags); BinaryObjectHeader.Write(header, _stream, pos); Stream.Seek(pos + len, SeekOrigin.Begin); // Seek to the end } finally { _schema.PopSchema(schemaIdx); } // Apply structure updates if any. _curStruct.UpdateWriterStructure(this); // Restore old frame. _curTypeId = oldTypeId; _curConverter = oldConverter; _curMapper = oldMapper; _curRawPos = oldRawPos; _curPos = oldPos; _curStruct = oldStruct; } else { // Are we dealing with a well-known type? var handler = BinarySystemHandlers.GetWriteHandler(type); if (handler == null) // We did our best, object cannot be marshalled. { throw new BinaryObjectException("Unsupported object type [type=" + type + ", object=" + obj + ']'); } handler(this, obj); } }
/** <inheritDoc /> */ public IBinaryObjectBuilder SetField <T>(string fieldName, T val) { return(SetField0(fieldName, new BinaryBuilderField(typeof(T), val, BinarySystemHandlers.GetTypeId(typeof(T))))); }