public void Serialize(ref byte[] buffer, ref int offset, Person value) { SerializerBinary.WriteString(ref buffer, ref offset, value.Name); SerializerBinary.WriteInt32(ref buffer, ref offset, value.Health); PersonFormatter.Serialize(ref buffer, ref offset, value.BestFriend); // Important: // You might be tempted to just recursively call Serialize again for 'BestFriend', but that won't work! // Do not think you can manually serialize other instances. // It may look like that the object injected into "PersonFormatter" is just 'MyCustomPersonFormatter' itself again, // but that's not the case! // In fact, what you get is a lot of magic behind the scenes that deals with a ton of edge cases (object references, and reference loop handling, and more) }
public void Serialize(ref byte[] buffer, ref int offset, Person value) { SerializerBinary.WriteString(ref buffer, ref offset, value.Name); SerializerBinary.WriteInt32(ref buffer, ref offset, value.Health); // !! Important - Read below! PersonFormatter.Serialize(ref buffer, ref offset, value.BestFriend); // You might be tempted to just recursively call your own Serialize method (this method) again for 'BestFriend', but that won't work! // That won't work because Ceras does many things behind the scenes to make reference-loops work. // // Think about it like this: // When we want to serialize '.BestFriend' and someone is their own best friend (silly, i know :P) then we'd want the serialized data to // say "this object was already written, look it up here..." // Otherwise we'd get into an infinite loop, which is exactly what is happening if we'd just write "this.Serialize(ref buffer, ref offset, value.BestFriend);" here. // // Now, as for the 'PersonFormatter' field in this class. // Ceras can inject fields of type 'IFormatter' and 'CerasSerializer' into all its formatters. // So, even though it may look like that the object injected into "PersonFormatter" is just 'MyCustomPersonFormatter' itself again, that's not the case! // // In case you are interested in what's going on behind the scenes: // Ceras actually injects a 'ReferenceFormatter<Person>' into our 'PersonFormatter' field, which deals with reference loops. }
public void Serialize(ref byte[] buffer, ref int offset, Type type) { // Null if (type == null) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias); return; } var typeCache = _serializer.InstanceData.TypeCache; // Existing if (typeCache.TryGetExistingObjectId(type, out int id)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias); return; } // Mode: New // Is it a composite type that we have to split into its parts? (aka any generic) bool isClosed = !type.ContainsGenericParameters; if (isClosed && type.IsGenericType) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewGeneric, Bias); // Split and write // Base var baseType = type.GetGenericTypeDefinition(); Serialize(ref buffer, ref offset, baseType); // Args var genericArgs = type.GetGenericArguments(); SerializerBinary.WriteByte(ref buffer, ref offset, (byte)(genericArgs.Length)); // We need count. Ex: Action<T1> and Action<T1, T2> share the name for (int i = 0; i < genericArgs.Length; i++) { Serialize(ref buffer, ref offset, genericArgs[i]); } // Register composite type typeCache.RegisterObject(type); } else { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewSingle, Bias); // Open generic, something that can be serialized alone var typeName = _typeBinder.GetBaseName(type); // Name SerializerBinary.WriteString(ref buffer, ref offset, typeName); // Register single type typeCache.RegisterObject(type); } // todo: do we put this only in the if or else part? or is it ok here? it should be ok, since we want to embed the schema of every type if (_serializer.Config.VersionTolerance == VersionTolerance.AutomaticEmbedded) { if (!CerasSerializer.FrameworkAssemblies.Contains(type.Assembly)) { _serializer.WriteSchemaForType(ref buffer, ref offset, type); } } }
public void Serialize(ref byte[] buffer, ref int offset, Type type) { // Null if (type == null) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias); return; } var typeCache = _serializer.InstanceData.TypeCache; // Existing if (typeCache.TryGetExistingObjectId(type, out int id)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias); return; } // Mode: New // Is it a composite type that we have to split into its parts? (aka any generic) bool isClosed = !type.ContainsGenericParameters; if (isClosed && type.IsGenericType) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewComposite, Bias); // Split and write // Base var baseType = type.GetGenericTypeDefinition(); Serialize(ref buffer, ref offset, baseType); // Args var genericArgs = type.GetGenericArguments(); SerializerBinary.WriteByte(ref buffer, ref offset, (byte)(genericArgs.Length)); // We need count. Ex: Action<T1> and Action<T1, T2> share the name. for (int i = 0; i < genericArgs.Length; i++) { Serialize(ref buffer, ref offset, genericArgs[i]); } // Register composite type typeCache.RegisterObject(type); } else { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewSingle, Bias); // Open generic, something that can be serialized alone var typeName = _typeBinder.GetBaseName(type); // Name SerializerBinary.WriteString(ref buffer, ref offset, typeName); // Register single type typeCache.RegisterObject(type); } }
public void Serialize(ref byte[] buffer, ref int offset, T value) { var str = value.ToString(); SerializerBinary.WriteString(ref buffer, ref offset, str); }
public void Serialize(ref byte[] buffer, ref int offset, string value) { SerializerBinary.WriteString(ref buffer, ref offset, value); }
public void Serialize(ref byte[] buffer, ref int offset, Uri value) { SerializerBinary.WriteString(ref buffer, ref offset, value.OriginalString); }