/// <summary>Register type.</summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> public void Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { if (type.GetInterface(typeof(IBinarizable).Name) != null) return; List<FieldInfo> fields = new List<FieldInfo>(); Type curType = type; while (curType != null) { foreach (FieldInfo field in curType.GetFields(Flags)) { if (!field.IsNotSerialized) fields.Add(field); } curType = curType.BaseType; } IDictionary<int, string> idMap = new Dictionary<int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); Descriptor desc = new Descriptor(fields); _types[type] = desc; }
/// <summary> /// Constructor. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="typeName">Type name.</param> /// <param name="userType">User type flag.</param> /// <param name="nameMapper">Name converter.</param> /// <param name="idMapper">Mapper.</param> /// <param name="serializer">Serializer.</param> /// <param name="keepDeserialized">Whether to cache deserialized value in IBinaryObject</param> /// <param name="affKeyFieldName">Affinity field key name.</param> public BinaryFullTypeDescriptor( Type type, int typeId, string typeName, bool userType, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, IBinarySerializer serializer, bool keepDeserialized, string affKeyFieldName) { _type = type; _typeId = typeId; _typeName = typeName; _userType = userType; _nameMapper = nameMapper; _idMapper = idMapper; _serializer = serializer; _keepDeserialized = keepDeserialized; _affKeyFieldName = affKeyFieldName; }
/// <summary> /// Gets the name of the type according to current name mapper. /// See also <see cref="ResolveType"/>. /// </summary> public string GetTypeName(Type type, IBinaryNameMapper mapper = null) { return(GetTypeName(type.AssemblyQualifiedName, mapper)); }
/// <summary> /// Gets the serializer. /// </summary> private static IBinarySerializerInternal GetSerializer(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, Type type, int typeId, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper, ILogger log) { var serializer = (typeCfg != null ? typeCfg.Serializer : null) ?? (cfg != null ? cfg.Serializer : null); if (serializer == null) { if (type.GetInterfaces().Contains(typeof(IBinarizable))) { return(BinarizableSerializer.Instance); } if (type.GetInterfaces().Contains(typeof(ISerializable))) { LogSerializableWarning(type, log); return(new SerializableSerializer(type)); } serializer = new BinaryReflectiveSerializer(); } var refSerializer = serializer as BinaryReflectiveSerializer; return(refSerializer != null ? refSerializer.Register(type, typeId, nameMapper, idMapper) : new UserSerializerProxy(serializer)); }
/// <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 enums. if (type.IsEnum) { WriteEnum(obj); return; } // Handle special case for builder. if (WriteBuilderSpecials(obj)) { return; } // Suppose that we faced normal object and perform descriptor lookup. IBinaryTypeDescriptor desc = _marsh.GetDescriptor(type); if (desc != null) { // 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); // 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); var dataEnd = _stream.Position; // Write schema var schemaOffset = dataEnd - pos; int schemaId; var flags = desc.UserType ? BinaryObjectHeader.Flag.UserType : BinaryObjectHeader.Flag.None; 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 (_curRawPos > 0) { _stream.WriteInt(_curRawPos - 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 = BinaryObjectHeader.Size; } if (_curRawPos > 0) { flags |= BinaryObjectHeader.Flag.HasRaw; } var len = _stream.Position - pos; var hashCode = desc.EqualityComparer != null ? desc.EqualityComparer.GetHashCode(Stream, pos + BinaryObjectHeader.Size, dataEnd - pos - BinaryObjectHeader.Size, _schema, schemaIdx, _marsh, desc) : obj.GetHashCode(); var header = new BinaryObjectHeader(desc.TypeId, 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. _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 BinaryUtils.GetUnsupportedTypeException(type, obj); } if (handler.SupportsHandles && WriteHandle(_stream.Position, obj)) { return; } handler.Write(this, obj); } }
/// <summary> /// Gets the serializer. /// </summary> private static IBinarySerializerInternal GetSerializer(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, Type type, int typeId, IBinaryNameMapper nameMapper, IBinaryIdMapper idMapper) { var serializer = typeCfg.Serializer ?? cfg.DefaultSerializer; if (serializer == null) { if (type.GetInterfaces().Contains(typeof(IBinarizable))) { return(BinarizableSerializer.Instance); } serializer = new BinaryReflectiveSerializer(); } var refSerializer = serializer as BinaryReflectiveSerializer; return(refSerializer != null ? refSerializer.Register(type, typeId, nameMapper, idMapper) : new UserSerializerProxy(serializer)); }